internal static List <string> GetSynonyms(clsTemplate template)
        {
            //* get all names that are associated with templete
            List <string> syns = new List <string>(3);

            for (int i = 0; i < NameToTemplate.Count; i++)
            {
                clsTemplate t = NameToTemplate.Values[i];
                if (template == t)
                {
                    syns.Add(NameToTemplate.Keys[i]);
                }
            }
            return(syns);
        }
        //internal static List<string> GetMatchingChordNames(bool[] inpc, int root) {
        //  //* return matching chord names
        //  int length = 0;
        //  List<string> names = new List<string>();
        //  foreach (bool tf in inpc) if (tf) length++;
        //  if (length < 3 || length > 4) return names;  //empty list - only 3, 4 note chords checked
        //  bool[] pc0 = new bool[12];  //pcs root C
        //  for (int i = 0; i < 12; i++) {
        //    if (inpc[i]) {
        //      int p = (i - root).Mod12();  //root C
        //      pc0[p] = true;
        //    }
        //  }
        //  foreach (clsTemplate t in Templates) {
        //    if (t.PC.SequenceEqual(pc0)) names.Add(t.Name);
        //  }
        //  return names;
        //}

        internal static clsScore GetTopChord(bool[] inpc, clsKeyTicks mkey, int maxtypenomatch,
                                             clsMTime.clsBBT bbt, out string chordname, out List <int> chnotes)
        {
            int length = 0;

            foreach (bool tf in inpc)
            {
                if (tf)
                {
                    length++;
                }
            }
            if (length < 2)
            {
                chordname = "";
                chnotes   = null;
                return(null);
            }
            List <clsScore> chlist = GetChords(inpc, mkey, bbt);

            for (int i = 0; i < chlist.Count; i++)
            {
                //clsTemplate t = ChordAnalysis.Templates[chlist[i].TIndex];
                clsTemplate t = ChordAnalysis.USToTemplate.Values[chlist[i].TIndex];
                if (chlist[i].Score == t.Length) //exact match (but may not be unique)
                {
                    chordname = t.Name;
                    chnotes   = chlist[i].ChNotes;
                    return(chlist[i]);
                }
                if (t.Rank > maxtypenomatch)
                {
                    continue;                   //no match and uncommon chord
                }
                chordname = t.Name;
                chnotes   = chlist[i].ChNotes;
                return(chlist[i]);
            }
            chordname = "";
            chnotes   = null;
            return(null);
        }
            internal int Chord     = -1;          //index to Templates

            internal void CalcScore()
            {
                List <clsTemplate> tlist = new List <clsTemplate>();
                int pos   = 0; //positive evidence
                int neg   = 0; //negative evidence
                int miss  = 0; //misses
                int score = 0;

                for (int chd = 0; chd < tlist.Count; chd++) //for each chord template
                {
                    clsTemplate template = tlist[chd];
                    if (template.Name == "***")
                    {
                        break;                //end stop
                    }
                    foreach (int pc in OnCount)
                    {
                        if (pc > 0)
                        {
                            if (template.PC[pc])
                            {
                                pos++;
                            }
                            else
                            {
                                neg++;
                            }
                        }
                        else if (template.PC[pc])
                        {
                            miss++;
                        }
                    }
                    score = pos - neg - miss;
                    if (score > Score)
                    {
                        Score = score;
                        Chord = chd;
                    }
                }
            }
        internal static string LoadTemplates()
        {
            if (!File.Exists(Cfg.ChordNamesDatFilePath))
            {
                return("Chord Names file not found");
            }
            List <string> lines = Utils.ReadLinesIgnoreComments(Cfg.ChordNamesDatFilePath);

            if (lines == null)
            {
                return("ChordNames File Load Error");
            }

            NameToTemplate    = new SortedList <string, clsTemplate>();
            USToTemplate      = new SortedList <ushort, clsTemplate>();
            FileSeqToTemplate = new SortedList <int, clsTemplate>();

            for (int i = 0; i < lines.Count; i++)
            {
                string   line = lines[i];
                string[] ff   = line.Split(new char[] { ',' });
                if (ff.Length < 4)
                {
                    return("ChordNames file  - invalid field count found at or around line " + i);
                }

                List <string> names = new List <string>();
                int           rank = 0, j = 0;
                for (j = 0; j < ff.Length; j++)
                {
                    if (int.TryParse(ff[j], out rank) && rank < 0)
                    {
                        break;                                   //first negative int
                    }
                    string name = ff[j].Trim();
                    if (name != "*")
                    {
                        names.Add(name);
                    }
                }
                rank = -rank;

                int        note;
                List <int> chord = new List <int>(5);
                chord.Add(0); //root always C
                for (++j; j < ff.Length; j++)
                {
                    if (!int.TryParse(ff[j], out note))
                    {
                        return("ChordNames file  - invalid line found at or around line " + i);
                    }
                    chord.Add(note);
                }

                clsTemplate t = new clsTemplate(names[0], rank, chord.ToArray());
                FileSeqToTemplate.Add(i, t);
                ushort us = BoolArrayToUShort(t.PC);
                USToTemplate.Add(us, t);
                foreach (string name in names)
                {
                    NameToTemplate.Add(name.ToLower(), t);
                }
            }
            string msg = LoadRanks();

            if (msg != "")
            {
                MessageBox.Show(msg);
            }
            return("");

            /*
             * //Stopwatch SW = new Stopwatch();
             * //SW.Start();
             * foreach (clsTemplate t in MainTemplates) t.GetHash();
             * //* NOTE *******************************************
             * //* C6 = Am7; Cm6 = Am7b5; Csus = Fsus2
             * //* NOTE *******************************************
             *
             * //Debug.WriteLine("ChordAnalysis: InitTemplates: InvSyms millisecs = " + SW.ElapsedMilliseconds);
             * //for (int i = 0; i < MainTemplates.Length; i++) Debug.WriteLine(i + ": " + MainTemplates[i].Hash);
             * //SW.Stop();
             *
             * for (int i = 0; i < MainTemplates.Length; i++) {
             * for (int j = i + 1; j < MainTemplates.Length; j++) {
             *  if (MainTemplates[i].Hash > 0 && MainTemplates[i].Hash == MainTemplates[j].Hash) {
             *    MainTemplates[i].InvSyns.Add(MainTemplates[j]);
             *    MainTemplates[j].InvSyns.Add(MainTemplates[i]);
             *  }
             * }
             * }
             */

            //foreach (clsTemplate t in MainTemplates) {
            //  if (t.InvSyns.Count > 0) {
            //    Debug.Write("InvSyms for " + t.Name + ": ");
            //    foreach (clsTemplate tt in t.InvSyns) Debug.Write(tt.Name);
            //    Debug.WriteLine("");
            //  }
            //}

            //return "";
        }