public async void GenerateBeatmap()
        {
            if (State != EditorState.READY)
            {
                return;
            }

            // pre
            SetState(EditorState.GENERATING_BEATMAP);

            // main phase
            Beatmap exportBeatmap = NewBeatmap.Copy();

            ModifyBeatmapMetadata(exportBeatmap, BpmMultiplier, ChangePitch);
            if (!File.Exists(JunUtils.GetBeatmapDirectoryName(OriginalBeatmap) + "\\" + exportBeatmap.AudioFilename))
            {
                string inFile  = $"{Path.GetDirectoryName(OriginalBeatmap.Filename)}\\{OriginalBeatmap.AudioFilename}";
                string outFile = $"{Path.GetDirectoryName(exportBeatmap.Filename)}\\{exportBeatmap.AudioFilename}";
                await Task.Run(() => SongSpeedChanger.GenerateAudioFile(inFile, outFile, BpmMultiplier, ChangePitch));

                // take note of this mp3 in a text file, so we can clean it up later
                string mp3ManifestFile = Properties.Settings.Default.SongsFolder + "\\modified_mp3_list.txt";
                using (var writer = File.AppendText(mp3ManifestFile))
                {
                    string beatmapFolder   = Path.GetDirectoryName(exportBeatmap.Filename).Replace(Properties.Settings.Default.SongsFolder + "\\", "");
                    string mp3RelativePath = beatmapFolder + "\\" + exportBeatmap.AudioFilename;
                    writer.WriteLine(mp3RelativePath + " | " + exportBeatmap.Filename);
                }
            }
            exportBeatmap.Save();

            // post
            form.PlayDoneSound();
            SetState(EditorState.READY);
        }
        private async void ServiceBeatmapChangeRequest()
        {
            // acquire mutually exclusive entry into this method
            serviceBeatmapRequestLocked = true;

            Beatmap candidateOriginalBeatmap = null, candidateNewBeatmap = null;

            while (completedBeatmapRequest == null || completedBeatmapRequest.RequestNumber != mapChangeRequests.Last().RequestNumber)
            {
                completedBeatmapRequest  = mapChangeRequests.Last();
                candidateOriginalBeatmap = await Task.Run(() => LoadBeatmap(mapChangeRequests.Last().Name));

                if (candidateOriginalBeatmap != null)
                {
                    candidateNewBeatmap = candidateOriginalBeatmap.Copy();
                    ModifyBeatmapTiming(candidateOriginalBeatmap, candidateNewBeatmap, BpmMultiplier);

                    // Apply bpm scaled settings
                    if (ScaleAR)
                    {
                        candidateNewBeatmap.ApproachRate = DifficultyCalculator.CalculateMultipliedAR(candidateOriginalBeatmap, BpmMultiplier);
                    }
                    if (ScaleOD)
                    {
                        candidateNewBeatmap.OverallDifficulty = DifficultyCalculator.CalculateMultipliedOD(candidateOriginalBeatmap, BpmMultiplier);
                    }

                    // Apply locked settings
                    if (HpIsLocked)
                    {
                        candidateNewBeatmap.HPDrainRate = lockedHP;
                    }
                    if (CsIsLocked)
                    {
                        candidateNewBeatmap.CircleSize = lockedCS;
                    }
                    if (ArIsLocked)
                    {
                        candidateNewBeatmap.ApproachRate = lockedAR;
                    }
                    if (OdIsLocked)
                    {
                        candidateNewBeatmap.OverallDifficulty = lockedOD;
                    }
                }

                // if a new request came in, invalidate candidate beatmap and service the new request
            }

            // no new requests, we can commit to using this beatmap
            OriginalBeatmap = candidateOriginalBeatmap;
            NewBeatmap      = candidateNewBeatmap;
            if (OriginalBeatmap == null)
            {
                SetState(EditorState.NOT_READY);
                NotReadyReason = BadBeatmapReason.ERROR_LOADING_BEATMAP;
                BeatmapSwitched?.Invoke(this, EventArgs.Empty);
            }
            else
            {
                if (OriginalBeatmap.HitObjects.Count == 0)
                {
                    SetState(EditorState.NOT_READY);
                    NotReadyReason = BadBeatmapReason.EMPTY_MAP;
                    BeatmapSwitched?.Invoke(this, EventArgs.Empty);
                }
                else if (OriginalBeatmap.Mode != GameMode.osu)
                {
                    SetState(EditorState.NOT_READY);
                    NotReadyReason = BadBeatmapReason.DIFF_NOT_OSUSTD;
                    BeatmapSwitched?.Invoke(this, EventArgs.Empty);
                }
                else
                {
                    SetState(EditorState.READY);
                    RequestDiffCalc();
                    BeatmapSwitched?.Invoke(this, EventArgs.Empty);
                    BeatmapModified?.Invoke(this, EventArgs.Empty);
                }
            }
            ControlsModified?.Invoke(this, EventArgs.Empty);
            serviceBeatmapRequestLocked = false;
        }