Inheritance: BeatmapInfo
 private void HandleReplayChanged(Replay r, Beatmap b)
 {
     Chart.SuspendLayout();
     Chart.Series[0].Points.Clear();
     Chart.ChartAreas[0].AxisX.ScaleView.ZoomReset(0);
     Chart.ChartAreas[0].AxisY.ScaleView.ZoomReset(0);
     for (int i = 0; i < oRA.Data.ReplayObjects.Count; i++ )
     {
         Chart.Series[0].Points.AddXY(i + 1, Math.Sqrt(Math.Pow(oRA.Data.ReplayObjects[i].Frame.X - oRA.Data.ReplayObjects[i].Object.Location.X, 2) + 
                                             Math.Pow(oRA.Data.ReplayObjects[i].Frame.Y - oRA.Data.ReplayObjects[i].Object.Location.Y, 2)));
     }
     Chart.ResumeLayout();
 }
 private void HandleReplayChanged(Replay r, Beatmap b)
 {
     Chart.SuspendLayout();
     Chart.Series[3].Points.Clear();
     Chart.ChartAreas[0].AxisX.ScaleView.ZoomReset(0);
     Chart.ChartAreas[0].AxisY.ScaleView.ZoomReset(0);
     Chart.ChartAreas[0].AxisY.Minimum = -oRA.Data.TimingWindows[0];
     Chart.ChartAreas[0].AxisY.Maximum = oRA.Data.TimingWindows[0];
     for (int i = 0; i < oRA.Data.ReplayObjects.Count; i++)
     {
         Chart.Series[3].Points.AddXY(i + 1, oRA.Data.ReplayObjects[i].Frame.Time - oRA.Data.ReplayObjects[i].Object.StartTime); 
     }         
     Chart.Series[0].Points.Clear();
     Chart.Series[0].Points.AddXY(0, oRA.Data.TimingWindows[2], -oRA.Data.TimingWindows[2]);
     Chart.Series[0].Points.AddXY(oRA.Data.ReplayObjects.Count, oRA.Data.TimingWindows[2], -oRA.Data.TimingWindows[2]);
     Chart.Series[1].Points.Clear();
     Chart.Series[1].Points.AddXY(0, oRA.Data.TimingWindows[1], -oRA.Data.TimingWindows[1]);
     Chart.Series[1].Points.AddXY(oRA.Data.ReplayObjects.Count, oRA.Data.TimingWindows[1], -oRA.Data.TimingWindows[1]);
     Chart.Series[2].Points.Clear();
     Chart.Series[2].Points.AddXY(0, oRA.Data.TimingWindows[0], -oRA.Data.TimingWindows[0]);
     Chart.Series[2].Points.AddXY(oRA.Data.ReplayObjects.Count, oRA.Data.TimingWindows[0], -oRA.Data.TimingWindows[0]);
     Chart.ResumeLayout();
 }
Beispiel #3
0
        public static void BeginGUI(int page)
        {
            while (true)
            {
                //Main GUI
                Console.Clear();
                Console.ForegroundColor = ConsoleColor.Green;
                Console.WriteLine(settings.ContainsSetting("v_osu! BPM Changer.exe")? "osu! BPM Changer v" + settings.GetSetting("v_osu! BPM Changer.exe") : "osu! BPM Changer v1.0.0");

                if (errorText != "")
                {
                    Console.ForegroundColor = ConsoleColor.Red;
                    Console.WriteLine(errorText);
                    Console.WriteLine("-------------------------------------------------------------------------------");
                    errorText = "";
                }
                Console.ForegroundColor = ConsoleColor.Green;
                double minBPM = double.MaxValue, maxBPM = double.MinValue;
                foreach (TimingPoint tp in BM.TimingPoints.Where(tp => tp.InheritsBPM == false))
                {
                    if (60000/tp.BpmDelay < minBPM)
                        minBPM = 60000 / tp.BpmDelay;
                    if (60000 / tp.BpmDelay > maxBPM)
                        maxBPM = 60000 / tp.BpmDelay;
                }
                if (Math.Abs(oldBPM) <= 0)
                    oldBPM = minBPM;
                if (versionSet == false)
                    BM.Version = oldVersion + minBPM + "BPM";
                Console.ForegroundColor = ConsoleColor.White;
                Console.WriteLine("Loaded beatmap " + BM.Source + (BM.Source != "" ? " (" + BM.Artist + ")" : BM.Artist) + " - " + BM.Title + " [" + oldVersion + "]\n");

                Console.ForegroundColor = ConsoleColor.Green;
                Console.WriteLine("BPM: " + minBPM + (Math.Abs(minBPM - maxBPM) > 0 ? " - " + maxBPM : ""));
                Console.WriteLine("Version: [" + BM.Version + "]");
                Console.WriteLine("Creator: " + BM.Creator);
                Console.WriteLine("Song format: " + (saveAsMP3 ? "MP3" : "WAV"));
                Console.ForegroundColor = ConsoleColor.White;
                Console.WriteLine("-------------------------------------------------------------------------------");

                if (updateExists)
                    DisplayUpdateString();

                string input;

                switch (page)
                {
                    case -1:
                        using (OpenFileDialog ofd = new OpenFileDialog())
                        {
                            ofd.Title = "Select Beatmap";
                            if (ofd.ShowDialog() == DialogResult.OK)
                            {
                                try
                                {
                                    BM = new Beatmap(ofd.FileName);
                                    oldVersion = BM.Version;
                                    oldBPM = 0;
                                    if (settings.ContainsSetting("customCreator"))
                                    {
                                        oldCreator = BM.Creator;
                                        BM.Creator = settings.GetSetting("customCreator");
                                    }
                                }
                                catch (Exception e)
                                {
                                    errorText = ("The beatmap could not be parsed. Please post the following error in the forums:\n" + e);
                                }
                            }
                        }
                        page = 0;
                        continue;

                    case 0:
                        Console.ForegroundColor = ConsoleColor.Yellow;
                        Console.WriteLine("Select option by typing any of the following numbers:");
                        Console.WriteLine("(1) Change BPM");
                        Console.WriteLine("(2) Change version");
                        Console.WriteLine("(3) Save beatmap\n");
                        Console.WriteLine("(8) Change song format");
                        Console.WriteLine("(9) Set custom creator");
                        Console.WriteLine("(0) Select another beatmap\n");

                        Console.ForegroundColor=ConsoleColor.White;
                        Console.WriteLine("Option: ");

                        int option;
                        ConsoleKeyInfo Kinfo = Console.ReadKey();
                        if (Kinfo.Key == ConsoleKey.Escape)
                        {
                            page = 0;
                            continue;
                        }
                        if (!int.TryParse(Kinfo.KeyChar.ToString(CultureInfo.InvariantCulture), out option))
                        {
                            errorText = "Entered option must be a numerical value.";
                            page = 0;
                            continue;
                        }
                        switch (option)
                        {
                            case 0:
                                page = -1;
                                continue;
                            case 1: case 2: case 3: case 8: case 9:
                                page = option;
                                continue;
                            default:
                                errorText = "Entered option value must be a valid option.";
                                page = 0;
                                continue;
                        }
                    case 1:
                        Console.ForegroundColor = ConsoleColor.Yellow;
                        Console.WriteLine("Enter the BPM increase:");
                        Console.WriteLine("(Example: N, +N, -N, *N, /N)\n");

                        Console.ForegroundColor = ConsoleColor.White;
                        Console.WriteLine("BPM: ");

                        input = Console.ReadLine();

                        Console.WriteLine("-------------------------------------------------------------------------------");
                        Console.WriteLine("Processing timingpoints...");
                        Console.ForegroundColor = ConsoleColor.Yellow;
                        bool error = false;
                        bool setRatio = false;
                        foreach (TimingPoint tp in BM.TimingPoints)
                        {
                            if (tp.InheritsBPM == false)
                            {
                                float currentBPM = 60000 / tp.BpmDelay;
                                float tempDbl;
                                float newBPM;
                                if (float.TryParse(input, out tempDbl) && !input.Contains("+") && !input.Contains("-"))
                                {
                                    if (!setRatio)
                                    {
                                        bpmRatio = oldBPM / tempDbl;
                                        setRatio = !setRatio;
                                    }
                                    newBPM = tempDbl;
                                }
                                else
                                {
                                    try
                                    {
                                        newBPM = (float)Convert.ToDouble(new DataTable().Compute(currentBPM + input, null));
                                        if (!setRatio)
                                        {
                                            bpmRatio = oldBPM / Convert.ToDouble(new DataTable().Compute(oldBPM + input, null));
                                            setRatio = !setRatio;
                                        }
                                    }
                                    catch
                                    {
                                        errorText = "BPM requires a numerical value or function.";
                                        error = true;
                                        break;
                                    }
                                }
                                float newDelay = 60000 / newBPM;
                                tp.BpmDelay = newDelay;
                                tp.Time = (int)(tp.Time * bpmRatio);
                            }
                            else
                            {
                                tp.Time = (int)(tp.Time * bpmRatio);
                            }
                        }
                        if (error)
                        {
                            page = 0;
                            continue;
                        }

                        Console.ForegroundColor = ConsoleColor.White;
                        Console.WriteLine("Processing events...");

                        Console.ForegroundColor = ConsoleColor.Yellow;

                        foreach (EventBase e in BM.Events)
                        {
                            e.StartTime = (int)(e.StartTime * bpmRatio);
                            if (e.GetType() == typeof(BreakEvent))
                                ((BreakEvent)e).EndTime = (int)(((BreakEvent)e).EndTime * bpmRatio);
                        }

                        Console.ForegroundColor = ConsoleColor.White;
                        Console.WriteLine("\nProcessing hitobjects...");
                        Console.ForegroundColor = ConsoleColor.Yellow;
                        foreach (CircleObject hO in BM.HitObjects)
                        {
                            hO.StartTime = (int)(hO.StartTime * bpmRatio);
                            if (hO.GetType() == typeof(SpinnerObject))
                                ((SpinnerObject)hO).EndTime = (int)(((SpinnerObject)hO).EndTime * bpmRatio);
                        }
                        page = 0;
                        continue;

                    case 2:
                        Console.ForegroundColor = ConsoleColor.Yellow;
                        Console.WriteLine("Enter the version:\n");

                        Console.ForegroundColor = ConsoleColor.White;
                        Console.WriteLine("Version: ");

                        input = Console.ReadLine();

                        BM.Version = input;
                        versionSet = true;
                        page = 0;
                        continue;

                    case 3:
                        string ext = BM.AudioFilename.Substring(BM.AudioFilename.LastIndexOf(".", StringComparison.InvariantCulture));

                        //temp1: Audio copy
                        //temp2: Decoded wav
                        //temp3: stretched file
                        //temp4: Encoded mp3
                        string temp1 = getTempFilename("mp3");
                        string temp2 = getTempFilename("wav");
                        string temp3 = getTempFilename("wav");
                        string temp4 = getTempFilename("mp3");

                        try
                        {
                            CopyFile(BM.Filename.Substring(0, BM.Filename.LastIndexOf("\\", StringComparison.InvariantCulture) + 1) + BM.AudioFilename, temp1);
                        }
                        catch
                        {
                            errorText = "Please make sure the beatmap set is not selected in the osu! menu and try again.";
                            page = 0;
                            continue;
                        }
                        BM.AudioFilename = BM.AudioFilename.Substring(0, BM.AudioFilename.LastIndexOf(".", StringComparison.InvariantCulture)) + NormalizeText(BM.Version) + (saveAsMP3 ? ".mp3" : ".wav");
                        Process p = new Process();
                        p.StartInfo.RedirectStandardOutput = true;
                        p.StartInfo.CreateNoWindow = false;
                        p.StartInfo.UseShellExecute = false;
                        p.StartInfo.FileName = "lame.exe";
                        p.StartInfo.Arguments = string.Format("--decode \"{0}\" \"{1}\"", temp1, temp2);
                        p.Start();
                        p.WaitForExit();

                        p.StartInfo.FileName = "soundstretch.exe";
                        p.StartInfo.Arguments = string.Format("\"{0}\" \"{1}\" -tempo={2}", temp2, temp3, (Math.Pow(bpmRatio, -1) - 1) * 100);
                        p.Start();
                        p.WaitForExit();
                        if (saveAsMP3)
                        {
                            p.StartInfo.FileName = "lame.exe";
                            p.StartInfo.Arguments = string.Format("\"{0}\" \"{1}\"", temp3, temp4);
                            p.Start();
                            p.WaitForExit();
                            CopyFile(temp4, BM.Filename.Substring(0, BM.Filename.LastIndexOf("\\", StringComparison.InvariantCulture)) + "\\" + BM.AudioFilename);
                        }
                        else
                            CopyFile(temp3, BM.Filename.Substring(0, BM.Filename.LastIndexOf("\\", StringComparison.InvariantCulture)) + "\\" + BM.AudioFilename);

                        Console.ForegroundColor = ConsoleColor.Green;
                        Console.WriteLine("Saving beatmap...");
                        BM.Filename = BM.Filename.Substring(0, BM.Filename.LastIndexOf("\\", StringComparison.InvariantCulture) + 1) + NormalizeText(BM.Artist) + " - " + NormalizeText(BM.Title) + " (" + NormalizeText(BM.Creator) + ")" + " [" + NormalizeText(BM.Version) + "].osu";
                        BM.Save(BM.Filename);

                        Console.WriteLine("Cleaning up...");
                        File.Delete(temp1);
                        File.Delete(temp2);
                        File.Delete(temp3);
                        File.Delete(temp4);

                        Console.WriteLine("Done! Press any key to go to menu.");
                        Console.ReadKey();
                        page = 0;
                        continue;

                    case 8:
                        saveAsMP3 = !saveAsMP3;
                        settings.AddSetting("customSaveAsMP3", Convert.ToInt32(saveAsMP3).ToString(CultureInfo.InvariantCulture));
                        settings.Save();
                        page = 0;
                        continue;
                    case 9:
                        Console.ForegroundColor = ConsoleColor.Yellow;
                        Console.WriteLine("Enter a custom creator name. This creator will be used for every single map version created with this program.");
                        Console.WriteLine("Enter /reset to remove custom creator.\n");

                        Console.ForegroundColor = ConsoleColor.White;
                        Console.WriteLine("Creator: ");

                        input = Console.ReadLine();

                        if (input == "/reset")
                        {
                            BM.Creator = oldCreator;
                            if (settings.ContainsSetting("customCreator"))
                            {
                                settings.DeleteSetting("customCreator");
                                settings.Save();
                            }

                        }
                        else
                        {
                            settings.AddSetting("customCreator", input);
                            settings.Save();
                            BM.Creator = input;
                        }
                        page = 0;
                        continue;
                }
                break;
            }
        }
Beispiel #4
0
        static void Main()
        {
            Application.CurrentCulture = new CultureInfo("en-US", false);
            Thread updaterThread = new Thread(UpdaterStart);
            updaterThread.IsBackground = true;
            updaterThread.Start();

            Console.ForegroundColor = ConsoleColor.White;
            using (OpenFileDialog ofd = new OpenFileDialog())
            {
                ofd.Title = "Select Beatmap";
                if (ofd.ShowDialog() == DialogResult.OK)
                {
                    try
                    {
                        BM = new Beatmap(ofd.FileName);
                        oldVersion = BM.Version;

                        if (settings.ContainsSetting("customCreator"))
                        {
                            oldCreator = BM.Creator;
                            BM.Creator = settings.GetSetting("customCreator");
                        }
                        if (settings.ContainsSetting("customSaveAsMP3"))
                        {
                            saveAsMP3 = Convert.ToBoolean(Convert.ToInt32(settings.GetSetting("customSaveAsMP3")));
                        }
                    }
                    catch (Exception e)
                    {
                        Console.ForegroundColor = ConsoleColor.Red;
                        Console.WriteLine("The beatmap could not be parsed. Please post the following error in the forums:\n" + e);
                        Console.ReadKey();
                        Application.Exit();
                    }
                    BeginGUI(0);
                    Console.ReadKey();
                }
            }
        }
        public void HandleReplayChanged(Replay r, Beatmap b)
        {
            float totalTime = 0;
            if (b.HitObjects.Count > 0)
                totalTime = b.HitObjects[b.HitObjects.Count - 1].StartTime - b.HitObjects[0].StartTime;

            tpDifficulty tp = new tpDifficulty();
            tp.tpHitObjects = new List<tpHitObject>(b.HitObjects.Count);
            foreach (CircleObject hitObject in b.HitObjects)
                tp.tpHitObjects.Add(new tpHitObject(hitObject));

            customListView1.Items.Clear();
            customListView1.Items.Add(new ListViewItem());
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_Format"], b.Format.ToString() }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_FName"], b.Filename }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_FSize"], File.OpenRead(b.Filename).Length + " bytes" }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_FHash"], r.MapHash }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_TotalHitObjects"], b.HitObjects.Count.ToString(CultureInfo.InvariantCulture) }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_MapAFN"], b.AudioFilename }));
            customListView1.Items.Add(new ListViewItem());
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_MapName"], b.Title + (!string.IsNullOrEmpty(b.TitleUnicode) && b.TitleUnicode != b.Title ? "(" + b.TitleUnicode + ")" : "") }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_MapArtist"], b.Artist + (!string.IsNullOrEmpty(b.ArtistUnicode) && b.ArtistUnicode != b.Artist ? "(" + b.ArtistUnicode + ")" : "") }));
            if (b.Source != null)
                customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_MapSource"], b.Source }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_MapCreator"], b.Creator }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_MapVersion"], b.Version }));
            if (b.BeatmapID != null)
                customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_MapID"], b.BeatmapID.ToString() }));
            if (b.BeatmapSetID != null)
                customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_MapSetID"], b.BeatmapSetID.ToString() }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_MapTags"], string.Join(", ", b.Tags) }));
            customListView1.Items.Add(new ListViewItem());
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_MapOD"], b.OverallDifficulty.ToString("0.00") }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_MapAR"], b.ApproachRate.ToString("0.00") }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_MapHP"], b.HPDrainRate.ToString("0.00") }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_MapCS"], b.CircleSize.ToString("0.00") }));
            customListView1.Items.Add(new ListViewItem());
            foreach (Combo combo in b.ComboColours)
            {
                ListViewItem li = new ListViewItem(oRA.Data.Language["oRA_MapComboColour"] + " " + combo.ComboNumber + ":");
                ListViewItem.ListViewSubItem colorItem = new ListViewItem.ListViewSubItem();
                colorItem.Text = combo.Colour.R + @", " + combo.Colour.G + @", " + combo.Colour.B;
                colorItem.ForeColor = Color.FromArgb(255, combo.Colour.R, combo.Colour.G, combo.Colour.B);
                li.SubItems.Add(colorItem);
                customListView1.Items.Add(li);
            }
            customListView1.Items.Add(new ListViewItem());
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_MapTotalTime"], TimeSpan.FromMilliseconds(totalTime).Minutes + ":" + TimeSpan.FromMilliseconds(totalTime).Seconds.ToString("00") }));
            totalTime = b.Events.Where(brk => brk.GetType() == typeof(BreakEvent)).Aggregate(totalTime, (current, brk) => current - (((BreakEvent)brk).EndTime - brk.StartTime));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_MapDrainTime"], TimeSpan.FromMilliseconds(totalTime).Minutes + ":" + TimeSpan.FromMilliseconds(totalTime).Seconds.ToString("00") }));
            if (tp.CalculateStrainValues())
            {
                double SpeedDifficulty = tp.CalculateDifficulty(tpDifficulty.DifficultyType.Speed);
                double AimDifficulty = tp.CalculateDifficulty(tpDifficulty.DifficultyType.Aim);
                double SpeedStars = Math.Sqrt(SpeedDifficulty) * tpDifficulty.STAR_SCALING_FACTOR;
                double AimStars = Math.Sqrt(AimDifficulty) * tpDifficulty.STAR_SCALING_FACTOR;
                double StarRating = SpeedStars + AimStars + Math.Abs(SpeedStars - AimStars) * tpDifficulty.EXTREME_SCALING_FACTOR;
                customListView1.Items.Add(new ListViewItem());
                customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_SpeedDifficulty"], SpeedDifficulty.ToString("0.00") }));
                customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_AimDifficulty"], AimDifficulty.ToString("0.00") }));
                customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_SpeedStars"], SpeedStars.ToString("0.00") }));
                customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_AimStars"], AimStars.ToString("0.00") }));
                customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_TotalStars"], StarRating.ToString("0.00") }));
            }

        }
        private void ReplaysList_AfterSelect(object sender, TreeViewEventArgs e)
        {
            //Failsafe
            if (!File.Exists(e.Node.Name))
            {
                MessageBox.Show(Language["oRA_ReplayInexistent"] + '\n' + e.Node.Name);
                return;
            }
            
            using (CurrentReplay = new Replay(e.Node.Name))
            {
                DataRow dR = DBHelper.GetRecord(DBConnection, "Beatmaps", "Hash", CurrentReplay.MapHash);
                if (dR != null)
                {
                    CurrentBeatmap = new Beatmap(dR["Filename"].ToString());

                    /* Start Timing Windows tab */

                    //Determine the timing windows for 300,100,50
                    //First modify the beatmap attributes according by player mods
                    if ((CurrentReplay.Mods & Modifications.HardRock) == Modifications.HardRock)
                    {
                        CurrentBeatmap.OverallDifficulty = Math.Min(CurrentBeatmap.OverallDifficulty *= 1.4f, 10);
                        CurrentBeatmap.CircleSize = CurrentBeatmap.CircleSize * 1.4f;

                        //Y-mirror objects
                        foreach (CircleObject obj in CurrentBeatmap.HitObjects)
                            obj.Location.Y = 384 - obj.Location.Y;
                    }
                    if ((CurrentReplay.Mods & Modifications.DoubleTime) == Modifications.DoubleTime)
                    {
                        CurrentBeatmap.OverallDifficulty = (float)Math.Min(13.0 / 3.0 + (2.0 / 3.0) * CurrentBeatmap.OverallDifficulty, 11);
                        CurrentBeatmap.ApproachRate = (float)Math.Min(13.0 / 3.0 + (2.0 / 3.0) * CurrentBeatmap.ApproachRate, 11);
                    }
                    if ((CurrentReplay.Mods & Modifications.HalfTime) == Modifications.HalfTime)
                    {
                        CurrentBeatmap.OverallDifficulty = (float)((3.0 / 2.0) * CurrentBeatmap.OverallDifficulty - 13.0 / 2.0);
                        CurrentBeatmap.ApproachRate = (float)((3.0 / 2.0) * CurrentBeatmap.ApproachRate - 13.0 / 2.0);
                    }
                    if ((CurrentReplay.Mods & Modifications.Easy) == Modifications.Easy)
                    {
                        CurrentBeatmap.OverallDifficulty = CurrentBeatmap.OverallDifficulty / 2;
                    }

                    //Timing windows are determined by linear interpolation
                    for (int i = 2; i >= 0; i--)
                    {
                        oRAData.TimingWindows[i] = CurrentBeatmap.OverallDifficulty < 5 ? (200 - 60 * i) + (CurrentBeatmap.OverallDifficulty) * ((150 - 50 * i) - (200 - 60 * i)) / 5 : (150 - 50 * i) + (CurrentBeatmap.OverallDifficulty - 5) * ((100 - 40 * i) - (150 - 50 * i)) / 5;
                    }

                    oRAData.ReplayObjects.Clear();

                    if (CurrentReplay.ReplayFrames.Count == 0)
                        return;

                    //Match up beatmap objects to replay clicks
                    HashSet<ReplayInfo> iteratedObjects = new HashSet<ReplayInfo>();
                    for (int i = 0; i < CurrentBeatmap.HitObjects.Count; i++)
                    {
                        //Todo: Consider if hitobject containspoint
                        ReplayInfo c = CurrentReplay.ClickFrames.Find(click => (Math.Abs(click.Time - CurrentBeatmap.HitObjects[i].StartTime) < oRAData.TimingWindows[2]) && !iteratedObjects.Contains(click)) ??
                                        CurrentReplay.ClickFrames.Find(click => (Math.Abs(click.Time - CurrentBeatmap.HitObjects[i].StartTime) < oRAData.TimingWindows[1]) && !iteratedObjects.Contains(click)) ??
                                        CurrentReplay.ClickFrames.Find(click => (Math.Abs(click.Time - CurrentBeatmap.HitObjects[i].StartTime) < oRAData.TimingWindows[0]) && !iteratedObjects.Contains(click));
                        if (c != null)
                        {
                            iteratedObjects.Add(c);
                            oRAData.ReplayObjects.Add(new ReplayObject { Frame = c, Object = CurrentBeatmap.HitObjects[i] });
                        }
                    }

                    ReplayTimeline.DataSource = iteratedObjects.ToList();
                    if (ReplayTimeline.Columns.Count > 0)
                    {
                        foreach (DataGridViewColumn c in ReplayTimeline.Columns)
                        {
                            c.SortMode = DataGridViewColumnSortMode.NotSortable;
                        }
                    }
                    if (ReplayTimeline.Rows.Count > 0)
                        ReplayTimeline.Rows[0].Selected = true;

                    oRAData.UpdateStatus(CurrentReplay, CurrentBeatmap);
                }
            }
        }
        public void HandleReplayChanged(Replay r, Beatmap b)
        {

            //Calculate UR and avg timing windows
            double unstableRate = 0, negativeErrorAverage = 0, positiveErrorAverage = 0, max = 0, min = 0, variance = 0;
            int nErrAvgCount = 0, pErrAvgCount = 0;
            double[] keyPAverage = new double[4];
            double[] keyNAverage = new double[4];
            double[] keyUnstableRate = new double[4];
            double[] keyVariance = new double[4];
            int[] keyPAverageCount = new int[4];
            int[] keyNAverageCount = new int[4];
            int[] keyCount = new int[4];

            for (int i = 0; i < oRA.Data.ReplayObjects.Count; i++)
            {
                double diff = oRA.Data.ReplayObjects[i].Frame.Time - oRA.Data.ReplayObjects[i].Object.StartTime;

                //For now, this will be used as the mean
                //We must calculate this before the actual unstable rate
                unstableRate += diff;

                //Because the enum has 5 and 10 which contain 1 and 2 K1 will trigger M1 and K2 will trigged M2
                //Therefore, we need to XOR K1,K1 out.
                //Or NOT, but it's quicker to XOR (compound assignment)
                //But we do not want to set the variable since it's used later, so we'll use a temp variable
                KeyData tKD = oRA.Data.ReplayObjects[i].Frame.Keys;
                if ((tKD & KeyData.K1) == KeyData.K1)
                {
                    tKD ^= KeyData.K1;
                    keyUnstableRate[0] += diff;
                    keyCount[0] += 1;
                }
                if ((tKD & KeyData.K2) == KeyData.K2)
                {
                    tKD ^= KeyData.K2;
                    keyUnstableRate[1] += diff;
                    keyCount[1] += 1;
                }
                if ((tKD & KeyData.M1) == KeyData.M1)
                {
                    keyUnstableRate[2] += diff;
                    keyCount[2] += 1;
                }
                if ((tKD & KeyData.M2) == KeyData.M2)
                {
                    keyUnstableRate[3] += diff;
                    keyCount[3] += 1;
                }
            }

            if (oRA.Data.ReplayObjects.Count > 0)
            {
                unstableRate /= oRA.Data.ReplayObjects.Count;
                for (int i = 0; i < 4; i++)
                {
                    if (keyCount[i] != 0)
                        keyUnstableRate[i] /= keyCount[i];
                }
            }

            for (int i = 0; i < oRA.Data.ReplayObjects.Count; i++)
            {
                double diff = oRA.Data.ReplayObjects[i].Frame.Time - oRA.Data.ReplayObjects[i].Object.StartTime;

                //This is a bit messy, but I'm too tired to improve it
                //Follows the same XOR-ing procedure as above
                KeyData tKD = oRA.Data.ReplayObjects[i].Frame.Keys;
                if (diff > 0)
                {
                    positiveErrorAverage += diff;
                    pErrAvgCount += 1;
                    if ((tKD & KeyData.K1) == KeyData.K1)
                    {
                        tKD ^= KeyData.K1;
                        keyVariance[0] += Math.Pow(diff - keyUnstableRate[0], 2);
                        keyPAverage[0] += diff;
                        keyPAverageCount[0] += 1;
                    }
                    if ((tKD & KeyData.K2) == KeyData.K2)
                    {
                        tKD ^= KeyData.K2;
                        keyVariance[1] += Math.Pow(diff - keyUnstableRate[0], 2);
                        keyPAverage[1] += diff;
                        keyPAverageCount[1] += 1;
                    }
                    if ((tKD & KeyData.M1) == KeyData.M1)
                    {
                        keyVariance[2] += Math.Pow(diff - keyUnstableRate[0], 2);
                        keyPAverage[2] += diff;
                        keyPAverageCount[2] += 1;
                    }
                    if ((tKD & KeyData.M2) == KeyData.M2)
                    {
                        keyVariance[3] += Math.Pow(diff - keyUnstableRate[0], 2);
                        keyPAverage[3] += diff;
                        keyPAverageCount[3] += 1;
                    }
                }
                else
                {
                    negativeErrorAverage += diff;
                    nErrAvgCount += 1;
                    if ((tKD & KeyData.K1) == KeyData.K1)
                    {
                        tKD ^= KeyData.K1;
                        keyVariance[0] += Math.Pow(diff - keyUnstableRate[0], 2);
                        keyNAverage[0] += diff;
                        keyNAverageCount[0] += 1;
                    }
                    if ((tKD & KeyData.K2) == KeyData.K2)
                    {
                        tKD ^= KeyData.K2;
                        keyVariance[1] += Math.Pow(diff - keyUnstableRate[0], 2);
                        keyNAverage[1] += diff;
                        keyNAverageCount[1] += 1;
                    }
                    if ((tKD & KeyData.M1) == KeyData.M1)
                    {
                        keyVariance[2] += Math.Pow(diff - keyUnstableRate[0], 2);
                        keyNAverage[2] += diff;
                        keyNAverageCount[2] += 1;
                    }
                    if ((tKD & KeyData.M2) == KeyData.M2)
                    {
                        keyVariance[3] += Math.Pow(diff - keyUnstableRate[0], 2);
                        keyNAverage[3] += diff;
                        keyNAverageCount[3] += 1;
                    }
                }
                variance += Math.Pow(diff - unstableRate, 2);

                if (diff > max)
                    max = diff;
                if (diff < min)
                    min = diff;
            }

            positiveErrorAverage = pErrAvgCount != 0 ? positiveErrorAverage / pErrAvgCount : 0;
            negativeErrorAverage = nErrAvgCount != 0 ? negativeErrorAverage / nErrAvgCount : 0;
            for (int i = 0; i < 4; i++)
            {
                //Calculate error rate
                if (keyPAverageCount[i] != 0)
                    keyPAverage[i] /= keyPAverageCount[i];
                if (keyNAverageCount[i] != 0)
                    keyNAverage[i] /= keyNAverageCount[i];
            }
            if (oRA.Data.ReplayObjects.Count > 0)
            {
                //Calculate unstable rate
                unstableRate = Math.Round(Math.Sqrt(variance / oRA.Data.ReplayObjects.Count) * 10, 2);
                for (int i = 0; i < 4; i++)
                {
                    if (keyCount[i] != 0)
                        keyUnstableRate[i] = Math.Round(Math.Sqrt(keyVariance[i] / keyCount[i]) * 10, 2);
                }
            }

            customListView1.Items.Clear();
            customListView1.Items.Add(new ListViewItem());
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_Format"], r.FileFormat.ToString(CultureInfo.InvariantCulture) }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_FName"], r.Filename }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_FSize"], File.OpenRead(r.Filename).Length + " " + oRA.Data.Language["oRA_bytes"] }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_FHash"], r.ReplayHash }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_ReplayFrames"], r.ReplayFrames.Count.ToString(CultureInfo.InvariantCulture) }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_KeysPressed"], r.ClickFrames.Count.ToString(CultureInfo.InvariantCulture) }));
            //Display individual key counts
            if (keyCount[0] != 0)
                customListView1.Items.Add(new ListViewItem(new[] { "K1 " + oRA.Data.Language["oRA_PressCount"], keyCount[0].ToString(CultureInfo.InvariantCulture) }));
            if (keyCount[1] != 0)
                customListView1.Items.Add(new ListViewItem(new[] { "K2 " + oRA.Data.Language["oRA_PressCount"], keyCount[1].ToString(CultureInfo.InvariantCulture) }));
            if (keyCount[2] != 0)
                customListView1.Items.Add(new ListViewItem(new[] { "M1 " + oRA.Data.Language["oRA_PressCount"], keyCount[2].ToString(CultureInfo.InvariantCulture) }));
            if (keyCount[3] != 0)
                customListView1.Items.Add(new ListViewItem(new[] { "M2 " + oRA.Data.Language["oRA_PressCount"], keyCount[3].ToString(CultureInfo.InvariantCulture) }));
            customListView1.Items.Add(new ListViewItem());
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_RepMode"], r.GameMode.ToString() }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_RepPlayer"], r.PlayerName }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_RepScore"], r.TotalScore.ToString(CultureInfo.InvariantCulture) }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_RepCombo"], r.MaxCombo.ToString(CultureInfo.InvariantCulture) }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_Rep300Count"], r.Count_300.ToString(CultureInfo.InvariantCulture) }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_Rep100Count"], r.Count_100.ToString(CultureInfo.InvariantCulture) }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_Rep50Count"], r.Count_50.ToString(CultureInfo.InvariantCulture) }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_RepMissCount"], r.Count_Miss.ToString(CultureInfo.InvariantCulture) }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_RepGekiCount"], r.Count_Geki.ToString(CultureInfo.InvariantCulture) }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_RepKatuCount"], r.Count_Katu.ToString(CultureInfo.InvariantCulture) }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_Grade"], GetRank(r.Count_300, r.Count_100, r.Count_50, r.Count_Miss, (r.Mods & Modifications.FlashLight) > 0 || (r.Mods & Modifications.Hidden) > 0) }));

            customListView1.Items.Add(new ListViewItem());
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_RepMods"], r.Mods.ToString() }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_ErrorRate"], negativeErrorAverage.ToString("0.00") + "ms ~ " + "+" + positiveErrorAverage.ToString("0.00") + "ms" }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_UnstableRate"], unstableRate.ToString("0.00") }));
            customListView1.Items.Add(new ListViewItem());
            if (keyNAverageCount[0] != 0 || keyPAverageCount[0] != 0)
                customListView1.Items.Add(new ListViewItem(new[] { "K1 " + oRA.Data.Language["oRA_ErrorRate"], keyNAverage[0].ToString("0.00") + "ms ~ " + "+" + keyPAverage[0].ToString("0.00") + "ms" }));
            if (keyNAverageCount[1] != 0 || keyPAverageCount[1] != 0)
                customListView1.Items.Add(new ListViewItem(new[] { "K2 " + oRA.Data.Language["oRA_ErrorRate"], keyNAverage[1].ToString("0.00") + "ms ~ " + "+" + keyPAverage[1].ToString("0.00") + "ms" }));
            if (keyNAverageCount[2] != 0 || keyPAverageCount[2] != 0)
                customListView1.Items.Add(new ListViewItem(new[] { "M1 " + oRA.Data.Language["oRA_ErrorRate"], keyNAverage[2].ToString("0.00") + "ms ~ " + "+" + keyPAverage[2].ToString("0.00") + "ms" }));
            if (keyNAverageCount[3] != 0 || keyPAverageCount[3] != 0)
                customListView1.Items.Add(new ListViewItem(new[] { "M2 " + oRA.Data.Language["oRA_ErrorRate"], keyNAverage[3].ToString("0.00") + "ms ~ " + "+" + keyPAverage[3].ToString("0.00") + "ms" }));
            if (keyCount[0] != 0)
                customListView1.Items.Add(new ListViewItem(new[] { "K1 " + oRA.Data.Language["oRA_UnstableRate"], keyUnstableRate[0].ToString("0.00") }));
            if (keyCount[1] != 0)
                customListView1.Items.Add(new ListViewItem(new[] { "K2 " + oRA.Data.Language["oRA_UnstableRate"], keyUnstableRate[1].ToString("0.00") }));
            if (keyCount[2] != 0)
                customListView1.Items.Add(new ListViewItem(new[] { "M1 " + oRA.Data.Language["oRA_UnstableRate"], keyUnstableRate[2].ToString("0.00") }));
            if (keyCount[3] != 0)
                customListView1.Items.Add(new ListViewItem(new[] { "M2 " + oRA.Data.Language["oRA_UnstableRate"], keyUnstableRate[3].ToString("0.00") }));
        }
 public void UpdateStatus(Replay Replay, Beatmap Beatmap)
 {
     if (ReplayChanged != null)
         ReplayChanged(Replay, Beatmap);
 }
 private void HandleReplayChanged(Replay r, Beatmap b)
 {
     CurrentBeatmap = b;
     LoadContent();
 }