static void Main(string[] args)
        {
            Console.WriteLine("Enter the filename without .txt:");
            var filename = Console.ReadLine();

            Console.WriteLine("Enter 1 for negative harmony, 2 for custom mapping:");
            var        mode = Console.ReadLine();
            NoteMapper noteMapper;
            NoteMapper triangleNoteMapper;

            Global.ReversePitchBends = mode == "1"; //we will revere the pitc ben if we are doing negative harmony only
            Console.WriteLine("Correct pitch bends(y/n)?:");

            Global.CorrectPitchBends = Console.ReadLine().ToLower().Trim() == "y";
            Console.WriteLine("Alter pitch bends(y/n)?:");

            Global.AlterPitchBends = Console.ReadLine().ToLower().Trim() == "y";
            if (mode == "1")
            {
                Console.WriteLine("Enter the key (e.g. C# for C sharp/D flat, C- for just C) major/minor doesn't matter:");
                var key = Console.ReadLine();
                Console.WriteLine("Enter base octave modifier (integer):");
                Global.baseOctaveModifier = Int32.Parse(Console.ReadLine());
                Console.WriteLine("Enter triangle octave modifier (integer):");
                Global.triangleOctaveModifier = Int32.Parse(Console.ReadLine());
                Console.WriteLine("Enter a comma-separated list of notes to raise 1 octave (0-11) or -1 if none:");
                Global.notesToRaise = Console.ReadLine().Split(',').ToList().Select(s => Int32.Parse(s.Trim())).ToList();
                Console.WriteLine("Enter a comma-separated list of notes to lower 1 octave (0-11) or -1 if none:");
                Global.notesToLower = Console.ReadLine().Split(',').ToList().Select(s => Int32.Parse(s.Trim())).ToList();
                noteMapper          = new NoteMapper(key, Global.baseOctaveModifier);
                triangleNoteMapper  = new NoteMapper(key, Global.triangleOctaveModifier);
            }
            else
            {
                Console.WriteLine("Enter the settings file name without .txt, or press enter for console:");
                var settingsName = Console.ReadLine();
                Console.WriteLine("Enter key to transpose the settings from C (0-11):");
                int key = Int32.Parse(Console.ReadLine());
                if (settingsName == "")
                {
                    Console.WriteLine("Create new settings file? Enter name for yes or press enter:");
                    var newSettingsName = Console.ReadLine();
                    if (newSettingsName == "")
                    {
                        noteMapper = new NoteMapper(Console.In, key);
                    }
                    else
                    {
                        var settingsFile  = new FileStream(newSettingsName + ".txt", FileMode.Create);
                        var settingsWrite = new StreamWriter(settingsFile);

                        var newSettingsReader = new ReaderIntoWriter(Console.In, settingsWrite);
                        noteMapper = new NoteMapper(newSettingsReader, key);
                        settingsWrite.Close();
                    }
                }
                else
                {
                    var settingsFile = new FileStream(settingsName + ".txt", FileMode.Open);
                    var settingsRead = new StreamReader(settingsFile);

                    noteMapper = new NoteMapper(settingsRead, key);
                    settingsRead.Close();
                }
                triangleNoteMapper = noteMapper;
            }

            var fileRead    = new FileStream(filename + ".txt", FileMode.Open);
            var fileWrite   = new FileStream(filename + " inverted.txt", FileMode.Create);
            var streamRead  = new StreamReader(fileRead);
            var streamWrite = new StreamWriter(fileWrite);
            var currentLine = "";

            while ((currentLine = streamRead.ReadLine()) != null)
            {
                if (!currentLine.StartsWith("ROW"))
                {
                    streamWrite.WriteLine(currentLine);
                    continue;
                }

                var newLine          = "";
                var currentLineSplit = currentLine.Split(':');
                for (int i = 0; i < currentLineSplit.Length; i++)
                {
                    if (i != 3)
                    {
                        newLine += currentLineSplit[i].InvertNotes(noteMapper, i) + ":";
                    }
                    else
                    {
                        newLine += currentLineSplit[i].InvertNotes(triangleNoteMapper, i) + ":";
                    }
                }
                newLine = newLine.Substring(0, newLine.Length - 1);
                streamWrite.WriteLine(newLine);
            }
            streamRead.Close();
            streamWrite.Close();
        }
        public static string InvertNotes(this string cell, NoteMapper noteMapper, int column)
        {
            var returns = cell;

            for (int i = 0; i < cell.Length - 2; i++)
            {
                var curSubstr = returns.Substring(i, 3);
                var newSubstr = curSubstr;
                foreach (var noteMapping in noteMapper.NoteMappings)
                {
                    if (curSubstr.Substring(0, 2) == noteMapping.FromNote)
                    {
                        int    parsedOctave;
                        string finalOctave;
                        //if no parse then is noise channel
                        if (Int32.TryParse(curSubstr.Substring(2, 1), out parsedOctave))
                        {
                            //log this note as the last one found in this column
                            Global.lastFromNoteInColumn[column] = Notes.Instance.NotesNameIndex[noteMapping.FromNote];
                            Global.lastOctaveInColumn[column]   = parsedOctave;
                            var unmodifiedOctave = parsedOctave;

                            var modifiedOctave = (unmodifiedOctave + noteMapping.OctaveModifier);

                            if (modifiedOctave < 10 && modifiedOctave >= 0)
                            {
                                finalOctave = modifiedOctave + "";
                            }
                            else
                            {
                                finalOctave = unmodifiedOctave + "";
                            }
                            newSubstr = noteMapping.ToNote + finalOctave;
                            if (noteMapping.NewPitchShiftInSemitones != null && Global.AlterPitchBends)
                            { // hack alert - replace first fx column with a pitch modifier if we are doing "custom map" for microtonal stuff
                                returns = returns.Remove(i + 9, 3);
                                returns = returns.Insert(i + 9, "P80");
                            }
                        }
                    }
                }
                returns = returns.Remove(i, 3);
                returns = returns.Insert(i, newSubstr);
            }
            //correct a pitch shifts in this cell based on previous note found in column
            var psi = returns.IndexOf('P'); //pitch shift index

            if (psi > -1 && Global.lastFromNoteInColumn.ContainsKey(column))
            {
                var lastNote    = Notes.Instance.NotesNameIndex[Global.lastFromNoteInColumn[column]];
                var noteMapping = noteMapper.NoteMappings.Single(nm => nm.FromNote == lastNote);
                if (noteMapping.NewPitchShiftInSemitones == null || !Global.AlterPitchBends) // new pitch shift is exclusive from PitchShiftCorrection
                {
                    var psSubString = returns.Substring(psi + 1, 2);
                    var hexPSValue  = Convert.ToInt32(psSubString, 16);
                    var hexPSDelta  = 128 - hexPSValue;
                    int newPSDelta;
                    if (Global.CorrectPitchBends)
                    {
                        newPSDelta = (int)Math.Round(hexPSDelta * noteMapping.PitchShiftCorrection);
                    }
                    else
                    {
                        newPSDelta = hexPSDelta;
                    }
                    if (Global.ReversePitchBends)
                    {
                        newPSDelta *= -1;
                    }
                    var newPSValue = 128 - newPSDelta;
                    while (newPSValue < 0)
                    {
                        newPSValue += 256;
                    }
                    var newPSHexString = newPSValue.ToString("X2");
                    returns = returns.Remove(psi + 1, 2);
                    returns = returns.Insert(psi + 1, newPSHexString);
                }
                else
                {
                    var diffFromC3 = (Notes.Instance.NotesNameIndex[noteMapping.ToNote] + Global.lastOctaveInColumn[column] * 12) - 36;
                    var newPSDelta = (int)Math.Round(NoteMapper.CalculateNewPitchShift(diffFromC3, noteMapping.NewPitchShiftInSemitones));
                    var newPSValue = 128 + newPSDelta;
                    while (newPSValue < 0)
                    {
                        newPSValue += 256;
                    }
                    var newPSHexString = newPSValue.ToString("X2");
                    returns = returns.Remove(psi + 1, 2);
                    returns = returns.Insert(psi + 1, newPSHexString);
                }
            }
            return(returns);
        }