private void convertButton_Click(object sender, EventArgs e)
        {
            IList<string> sourceFilePaths;
            allDif = difficultyAll.Checked;

            // Input file(s)
            using (var ofd = new OpenFileDialog())
            {
                if (rbAsciiTab.Checked)
                    ofd.Filter = "RS1 (*.dat, *.sng, *.xml) or RS2014 (*.psarc) files|*.dat;*.sng;*.xml;*.psarc";
                else
                    ofd.Filter = "RS2014 (*.psarc, *.xml) files|*.psarc;*.xml";

                ofd.Title = "Select RS1 and/or RS2014 CDLC files to convert";
                ofd.Multiselect = true;
                ofd.FileOk += OpenFileDialog_FileLimit; // Event handler

                if (ofd.ShowDialog() != DialogResult.OK)
                    return;
                sourceFilePaths = ofd.FileNames;
            }

            using (var fbd = new FolderBrowserDialog())
            {
                fbd.Description = "Select a folder for storing converted files.";
                fbd.ShowNewFolderButton = true;
                fbd.SelectedPath = outputDir;
                // fbd.SelectedPath = "D:\\Temp"; // for testing
                if (fbd.ShowDialog() != DialogResult.OK)
                    return;

                outputDir = fbd.SelectedPath;
            }

            Cursor.Current = Cursors.WaitCursor;
            foreach (var inputFilePath in sourceFilePaths)
            {
                string fileExtension = Path.GetExtension(inputFilePath).ToLower();
                switch (fileExtension)
                {
                    case ".xml":
                        if (rbGp5.Checked)
                        {
                            using (var obj = new Gp5Converter())
                                obj.XmlToGp5(inputFilePath, outputDir);
                        }
                        else
                        {
                        var fileName = Path.GetFileNameWithoutExtension(inputFilePath);
                        var splitPoint = fileName.LastIndexOf('_');
                        var arrangement = fileName.Substring(splitPoint + 1);
                        // skip any files for vocals and/or showlights
                        if (arrangement.ToLower() == "vocals" || arrangement.ToLower() == "showlights")
                            break;
                        Song rs1Song;
                        using (var obj = new Rs1Converter())
                            rs1Song = obj.XmlToSong(inputFilePath);
                        string sngFilePath;
                        using (var obj = new Rs1Converter())
                            sngFilePath = obj.SongToSngFilePath(rs1Song, Path.Combine(outputDir, Path.GetFileName(inputFilePath)));
                        using (var obj = new Sng2Tab())
                            obj.Convert(sngFilePath, outputDir, allDif);
                        if (File.Exists(sngFilePath))
                            File.Delete(sngFilePath);
                }
                break;
                    case ".dat":
                        using (var obj = new Sng2Tab())
                            obj.ExtractBeforeConvert(inputFilePath, outputDir, allDif);
                        break;
                    case ".sng":
                        using (var obj = new Sng2Tab())
                            obj.Convert(inputFilePath, outputDir, allDif);
                        break;
                    case ".psarc":
                        if (rbSongList.Checked)
                        {
                            using (var obj = new Rs2014Converter())
                                obj.PsarcSongList(inputFilePath, outputDir);
                            break;
                        }
                        var fileInfo = new FileInfo(inputFilePath);
                        // give user chance to abort big files
                        if (fileInfo.Length / 1000 > 15000)
                        {
                            if (MessageBox.Show(string.Format("{0} file size is {1:N00} KB{2}It may take a long time to extract and convert that much data.{2}{2}Do you want to continue?", Path.GetFileName(inputFilePath), (fileInfo.Length / 1000), Environment.NewLine), MESSAGEBOX_CAPTION, MessageBoxButtons.YesNo, MessageBoxIcon.Information) == DialogResult.No)
                                return;
                        }
                        using (var obj = new Rs2014Converter())
                            songList = obj.PsarcSongList(inputFilePath);
                        if (rbAsciiTab.Checked)
                        {
                            using (var form = new SongInfoForm())
                            {
                                form.PopSongInfo(songList);
                                do
                                    // waiting for user selection(s)
                                    form.ShowDialog();
                                while (form.SongListShort.Count == 0);
                                this.Refresh();
                                if (form.SongListShort[0].Identifier == "User Aborted")
                                    break;
                                Cursor.Current = Cursors.WaitCursor;
                                foreach (var song in form.SongListShort)
                                {
                                    Song2014 rs2014Song;
                                    using (var obj = new Rs2014Converter())
                                    {
                                        rs2014Song = obj.PsarcToSong2014(inputFilePath, song.Identifier, song.Arrangement);
                                        obj.Song2014ToAsciiTab(rs2014Song, outputDir, allDif);
                                    }
                                }
                            }
                            break;
                        }
                        // convert to *.gp5 file(s) optimized code for dll usage
                        if (!allDif && songList.Count == 1)
                            using (var obj = new Gp5Converter())
                                obj.PsarcToGp5(inputFilePath, outputDir);
                        else
                            if (!allDif && songList.Count > 1)
                            {
                                using (var form = new SongInfoForm())
                                {
                                    form.PopSongOnly(songList);
                                    //  songs only (merge all arrangements into single GP file)
                                    //  form.PopSongInfo(songList); // choose songs and arrangements
                                    do
                                        // waiting for user selection(s)
                                        form.ShowDialog();
                                    while (form.SongListShort.Count == 0);
                                    this.Refresh();
                                    if (form.SongListShort[0].Identifier == "User Aborted")
                                        break;
                                    Cursor.Current = Cursors.WaitCursor;
                                    using (var obj = new Gp5Converter())
                                        obj.PsarcToGp5(inputFilePath, outputDir, form.SongListShort);
                                }
                            }
                            // give user the option to select specific songs and arrangements
                            else
                                if (allDif)
                                {
                                    using (var form = new SongInfoForm())
                                    {
                                        form.PopSongInfo(songList);
                                        // choose songs and arrangements
                                        do
                                            // waiting for user selection(s)
                                            form.ShowDialog();
                                        while (form.SongListShort.Count == 0);
                                        this.Refresh();
                                        if (form.SongListShort[0].Identifier == "User Aborted")
                                            break;
                                        Cursor.Current = Cursors.WaitCursor;
                                        using (var obj = new Gp5Converter())
                                            obj.PsarcToGp5(inputFilePath, outputDir, form.SongListShort, "gp5", true);
                                    }
                                }
                        break;
                }
                Refresh();
            }

            Cursor.Current = Cursors.Default;

            if (MessageBox.Show("The conversion is complete.." + Environment.NewLine +
                "Would you like to open the folder?", MESSAGEBOX_CAPTION,
                MessageBoxButtons.YesNo, MessageBoxIcon.Information) == DialogResult.Yes)
                Process.Start(outputDir);
        }
 /// <summary>
 /// SngFilePath to ASCII Tablature
 /// </summary>
 /// <param name="inputFilePath"></param>
 /// <param name="outputDir"></param>
 /// <param name="allDif"></param>
 public void SngFilePathToAsciiTab(string inputFilePath, string outputDir, bool allDif)
 {
     using (var obj = new Sng2Tab())
         obj.Convert(inputFilePath, outputDir, allDif);
 }
        /// <summary>
        /// Song2014 to ASCII Tablature
        /// </summary>
        /// <param name="rs2014Song"></param>
        /// <param name="outputDir"></param>
        /// <param name="allDif"></param>
        public void Song2014ToAsciiTab(Song2014 rs2014Song, string outputDir, bool allDif)
        {
            if (rs2014Song == null || String.IsNullOrEmpty(outputDir)) return;
            // convert to Song
            Song rs1Song;
            using (var obj = new Rs2014Converter())
                rs1Song = obj.Song2014ToSong(rs2014Song);
            Console.WriteLine("Converted Song2014 To Song");

            //if (false) // write Xml files for debugging
            //{
            //    using (Rs2014Converter obj = new Rs2014Converter())
            //        obj.Song2014ToXml(rs2014Song, outputDir, true);
            //    using (Rs1Converter obj = new Rs1Converter())
            //        obj.SongToXml(rs1Song, outputDir, true);
            //}

            // convert to SngFile
            string rs1SngFilePath;
            using (var obj = new Rs1Converter())
                rs1SngFilePath = obj.SongToSngFilePath(rs1Song, outputDir);
            Console.WriteLine("Converted Song To SngFile");

            // convert to AsciiTab
            using (var s2Tab = new Sng2Tab())
                s2Tab.Convert(rs1SngFilePath, outputDir, allDif);
            Console.WriteLine("Converted SngFile To AsciiTab");

            if (File.Exists(rs1SngFilePath)) File.Delete(rs1SngFilePath);
        }