The congeneric score track. монофонический (моно) трек
Inheritance: IBaseObject
 /// <summary>
 /// The calculate.
 /// метод для подсчета приоритетов нот для каждого такта (Measure) 
 /// в монофоническом треке (CongenericScoretrack)
 /// </summary>
 /// <param name="congenericTrack">
 /// The congeneric track.
 /// </param>
 public void Calculate(CongenericScoreTrack congenericTrack)
 {
     foreach (Measure measure in congenericTrack.MeasureList)
     {
         Calculate(measure);
     }
 }
        /// <summary>
        /// The divide.
        /// </summary>
        /// <param name="congenericTrack">
        /// The congeneric track.
        /// </param>
        /// <param name="paramPauseTreatment">
        /// The param pause treatment.
        /// параметр как учитывать паузу :
        /// игнорировать, звуковой след предыдущего звука, вырожденныый звук
        /// </param>
        /// <param name="paramEqualFM">
        /// The param equal fm.
        /// как сравнивать ф-мотивы с секвентым переносом, либо нет
        /// </param>
        /// <returns>
        /// The <see cref="FmotivChain"/>.
        /// </returns>
        public FmotivChain Divide(CongenericScoreTrack congenericTrack, ParamPauseTreatment paramPauseTreatment, ParamEqualFM paramEqualFM)
        {
            // сохраняем имя цепи фмотивов как имя монотрека
            var priorityDiscover = new PriorityDiscover();
            var fmotivDivider = new FmotivDivider();
            var fmotivIdentifier = new FmotivIdentifier();

            // подсчет приоритетов
            priorityDiscover.Calculate(congenericTrack);

            // разбиение
            FmotivChain chain = fmotivDivider.GetDivision(congenericTrack, paramPauseTreatment);

            // нахождение одинаковых
            return fmotivIdentifier.GetIdentification(chain, paramPauseTreatment, paramEqualFM);
        }
        public void FmotivDividerEighthTest()
        {
            // создание и заполнения списка(ов) нот для такта(ов) монотрека
            var notes = new List<ValueNote>
            {
                new ValueNote(new Pitch(3, 'A', 0), new Duration(1, 8, false, 256), false, Tie.None, 0),
                new ValueNote(new Pitch(3, 'B', 0), new Duration(1, 8, false, 256), false, Tie.None, 2),
                new ValueNote((Pitch)null, new Duration(1, 8, false, 256), false, Tie.None, 1),
                new ValueNote(new Pitch(3, 'B', 0), new Duration(1, 8, false, 256), false, Tie.None, 2)
            };

            // создание атрибутов для такта(ов)
            var attributes = new Attributes(new Size(2, 4, 1024), new Key(0, "major"));

            // создание и заполнение такта(ов) списками нот и атрибутами
            var measures = new List<Measure> { new Measure(notes, (Attributes)attributes.Clone()) };

            // создание моно трека
            var unitrack = new CongenericScoreTrack("track1", measures);

            // создание объекта для деления монотрека на фмотивы
            var fmdivider = new FmotivDivider();

            // создание результирующей цепочки фмотивов
            // вычисление, опрделение, разбиение на  ф-мотивы данного монотрека
            FmotivChain fmchain = fmdivider.GetDivision(unitrack, (int)ParamPauseTreatment.Ignore);
            fmchain.Id = 0;

            // создание аналогов ф-мотивов, которые должны получиться, после разбиения
            // процедура определения одинаковых на данном этапе не производится
            var fmotiv1 = new Fmotiv("ПМТ", 0);
            fmotiv1.NoteList.Add(new ValueNote(new Pitch(3, 'A', 0), new Duration(1, 8, false, 256), false, Tie.None));
            fmotiv1.NoteList.Add(new ValueNote((Pitch)null, new Duration(1, 8, false, 256), false, Tie.None));
            fmotiv1.NoteList.Add(new ValueNote(new Pitch(3, 'B', 0), new Duration(1, 8, false, 256), false, Tie.None));
            fmotiv1.NoteList.Add(new ValueNote(new Pitch(3, 'B', 0), new Duration(1, 8, false, 256), false, Tie.None));

            // записываем ф-мотивы в цепь ф-мотивов, которая будет сравниваться с получившейся
            var fmchain1 = new FmotivChain { Id = 0, Name = "track1" };
            fmchain1.FmotivList.Add(fmotiv1);

            Assert.IsTrue(fmchain1.Equals(fmchain));
        }
        /// <summary>
        /// The get division.
        /// </summary>
        /// <param name="congenericTrack">
        /// The congeneric track.
        /// </param>
        /// <param name="paramPauseTreatment">
        /// The param pause treatment.
        /// </param>
        /// <returns>
        /// The <see cref="FmotivChain"/>.
        /// </returns>
        /// <exception cref="Exception">
        /// Thrown in many cases.
        /// </exception>
        public FmotivChain GetDivision(CongenericScoreTrack congenericTrack, ParamPauseTreatment paramPauseTreatment)
        {
            var chain = new FmotivChain { Name = congenericTrack.Name }; // выходная, результирующая цепочка разбитых ф-мотивов
            this.paramPauseTreatment = paramPauseTreatment;

            var fmotivBuffer = new Fmotiv(string.Empty);

            // буффер для накопления нот, для последующего анализа его содержимого
            var noteChain = new List<ValueNote>();

            // цепочка нот, куда поочередно складываются ноты из последовательности тактов
            // для дальнейшего их анализа и распределения по ф-мотивам.

            // заполняем NoteChain всеми нотам из данной монофонической цепи unitrack
            foreach (Measure measure in congenericTrack.MeasureList)
            {
                foreach (ValueNote note in measure.NoteList)
                {
                    noteChain.Add((ValueNote)note.Clone());
                }
            }

            // счетчик реальных нот/пауз для первой группировки в реальную нот
            int n = 0;

            // флаг который говорит, что была нота перемещена в буфер после последнего флага Next, для pause notetrace
            bool wasNote = false;

            // флаг, говорит что собралась очередная нота для рассмотрения
            bool next = false;

            // флаг, говорящий что собирается последовательность равнодлительных звуков (1,2 тип фмотива - ПМТ,ЧМТ)
            bool sameDurationChain = false;

            // флаг, говорящий что собирается возрастающая последовательность (3 тип фмотива)
            bool growingDurationChain = false;

            // флаг, говорящий что собирается комбинация - ПМТ/ЧМТ и возрастающая последовательность (4 тип фмотива)
            bool combination = false;

            // пока анализируемая цепь содержит элементы, идет выполнение анализа ее содержимого
            while (noteChain.Count > 0)
            {
                fmotivBuffer.NoteList.Add((ValueNote)noteChain[0].Clone());
                noteChain.RemoveAt(0);

                // проверка на наличие лиги у очередной ноты, если есть то заносим в буффер все ноты, объединенные данной лигой
                if (fmotivBuffer.NoteList[fmotivBuffer.NoteList.Count - 1].Tie != Tie.None)
                {
                    // если есть флаг начала лиги, то записываем в буфер все остальные лигованные ноты, пока не будет флага конца лиги
                    if (fmotivBuffer.NoteList[fmotivBuffer.NoteList.Count - 1].Tie == Tie.Start)
                    {
                        // TODO: желательно сделать проверку когда собирается очередная лига,
                        // не будет ли пуста цепь нот, до того как лига закончится (будет флаг конца лиги)
                        while (noteChain[0].Tie == Tie.StartStop)
                        {
                            // пока продолжается лига, заносим ноты в буфер
                            fmotivBuffer.NoteList.Add((ValueNote)noteChain[0].Clone());
                            noteChain.RemoveAt(0);
                        }

                        if (noteChain[0].Tie == Tie.Stop)
                        {
                            // если есть флаг конца лиги у очередной ноты, то заносим конечную ноту лиги в буфер
                            fmotivBuffer.NoteList.Add((ValueNote)noteChain[0].Clone());
                            noteChain.RemoveAt(0);

                            wasNote = true; // была нота пермещена в буфер

                            switch (paramPauseTreatment)
                            {
                                case ParamPauseTreatment.Ignore:
                                    // удаляем все паузы в возвращаемом объекте (0) (паузы игнорируются)
                                    // если у очередной ноты нет лиги, то проверяем: если нота - не пауза, то выставляем флаг о следущей рассматриваемой ноте
                                    if (fmotivBuffer.NoteList[fmotivBuffer.NoteList.Count - 1].Pitch.Count > 0)
                                    {
                                        next = true;
                                    }

                                    break;
                                case ParamPauseTreatment.NoteTrace:
                                    // длительность паузы прибавляется к предыдущей ноте, а она сама удаляется из текста (1) (пауза - звуковой след ноты)
                                    if (noteChain.Count > 0)
                                    {
                                        // если следующая не паузы то переходим к анализу буфера
                                        if (noteChain[0].Pitch.Count > 0)
                                        {
                                            next = true;
                                        }
                                    }
                                    else
                                    {
                                        next = true;
                                    }

                                    break;
                                case ParamPauseTreatment.SilenceNote:
                                    // Пауза - звук тишины, рассматривается как нота без высоты звучания (2)
                                    // ничего не треуется
                                    next = true;
                                    break;
                                default:
                                    throw new Exception("Error Fmotiv.PauseTreatment parameter contains wrong value!");
                            }
                        }
                        else
                        {
                            // когда лига не заканчивается флагом конца, то ошибка
                            throw new Exception("LibiadaMusic: FmotivDivider, wrong Tie organization!End!");
                        }
                    }
                    else
                    {
                        // когда начинается лига не с флага начала, а с какого то другого, то ошибка
                        throw new Exception("LibiadaMusic: FmotivDivider, wrong Tie organization!Begining!");
                    }
                }
                else
                {
                    // если у очередной ноты нет лиги
                    switch (paramPauseTreatment)
                    {
                        case ParamPauseTreatment.Ignore:
                            // удаляем все паузы в возвращаемом объекте (0) (паузы игнорируются)
                            // если у очередной ноты нет лиги, то проверяем: если нота - не пауза, то выставляем флаг о следущей рассматриваемой ноте
                            if (fmotivBuffer.NoteList[fmotivBuffer.NoteList.Count - 1].Pitch.Count > 0)
                            {
                                next = true;
                            }

                            break;
                        case ParamPauseTreatment.NoteTrace:
                            // длительность паузы прибавляется к предыдущей ноте, а она сама удаляется из текста (1) (пауза - звуковой след ноты)
                            // проверяем: если нота - не пауза, то выставляем флаг о следущей рассматриваемой ноте
                            if (fmotivBuffer.NoteList[fmotivBuffer.NoteList.Count - 1].Pitch.Count > 0)
                            {
                                wasNote = true;
                            }

                            if (noteChain.Count > 0)
                            {
                                // если следующая в н. тексте не пауза то переходим к анализу буфера
                                if ((noteChain[0].Pitch.Count > 0) && wasNote)
                                {
                                    next = true;
                                }
                            }
                            else
                            {
                                if (wasNote)
                                {
                                    next = true;
                                }
                            }

                            break;
                        case ParamPauseTreatment.SilenceNote:
                            // Пауза - звук тишины, рассматривается как нота без высоты звучания (2)
                            // ничего не треуется
                            next = true;
                            break;
                        default:
                            throw new Exception("Error Fmotiv.PauseTreatment parameter contains wrong value!");
                    }
                }

                // если готова (собрана) следущая нота для анализа
                if (next)
                {
                    // убираем флаг следущей готовой (собранной ноты), так как после анализа не известно что там будет
                    next = false;
                    wasNote = false;

                    if (ExtractNoteList(fmotivBuffer).Count == 1)
                    {
                        // сохранили сколько нот/пауз входит в первую рассматриваемую ноту
                        n = fmotivBuffer.NoteList.Count;
                    }

                    if (ExtractNoteList(fmotivBuffer).Count == 2)
                    {
                        // если длительность первой собранной ноты больше длительности второй собранной ноты
                        if (TempExtractor(fmotivBuffer, 0).Duration.Value > TempExtractor(fmotivBuffer, 1).Duration.Value)
                        {
                            // заносим ноты/паузы первой собранной ноты в очередной фмотив с типом ЧМТ, и удаляем из буфера
                            var fm = new Fmotiv("ЧМТ", chain.FmotivList.Count);
                            for (int i = 0; i < n; i++)
                            {
                                // заносим
                                fm.NoteList.Add((ValueNote)fmotivBuffer.NoteList[0].Clone());

                                // удаляем
                                fmotivBuffer.NoteList.RemoveAt(0);
                            }

                            // добавляем в выходную цепочку получившийся фмотив
                            chain.FmotivList.Add((Fmotiv)fm.Clone());

                            // сохранили n на случай если за этим фмотивом следует еще один ЧМТ
                            n = fmotivBuffer.NoteList.Count;

                            // сохранили сколько нот/пауз входит в первую рассматриваемую ноту
                        }
                        else
                        {
                            if (AnotherTempComparator(fmotivBuffer))
                            {
                                // выставляем флаг для сбора последовательности равнодлительных звуков
                                sameDurationChain = true;
                                n = fmotivBuffer.NoteList.Count; // сохранили сколько нот/пауз входит в буфер
                            }
                            else
                            {
                                if (SecondAnotherTempComparator(fmotivBuffer))
                                {
                                    // выставляем флаг для сбора возрастающей последовательности
                                    growingDurationChain = true;

                                    // сохранили сколько нот/пауз входит в буфер
                                    n = fmotivBuffer.NoteList.Count;
                                }
                            }
                        }
                    }

                    if (ExtractNoteList(fmotivBuffer).Count > 2)
                    {
                        if (sameDurationChain)
                        {
                            // если длительность предпоследнего меньше длительности последнего
                            if (TempExtractor(fmotivBuffer, ExtractNoteList(fmotivBuffer).Count - 2).Duration.Value <
                                TempExtractor(fmotivBuffer, ExtractNoteList(fmotivBuffer).Count - 1).Duration.Value)
                            {
                                var fmotivBuffer2 = new Fmotiv(string.Empty);

                                // помещаем в буффер2 последнюю собранную ноту - большей длительности чем все равнодлительные
                                // так как меняется в процессе
                                int count = fmotivBuffer.NoteList.Count;
                                for (int i = n; i < count; i++)
                                {
                                    fmotivBuffer2.NoteList.Add((ValueNote)fmotivBuffer.NoteList[n].Clone());
                                    fmotivBuffer.NoteList.RemoveAt(n);
                                }

                                // отправляем последовательность равнодлительных звуков на анализ, получаем цепочку фмотивов и заносим их в выходную последовательность
                                // заисключением последнего фмотива - он останется в буфере вместе с нотой длительность которой больше последней ноты этого фмотива
                                List<Fmotiv> dividedSameDuration = DivideSameDurationNotes(fmotivBuffer);
                                for (int i = 0; i < (dividedSameDuration.Count - 1); i++)
                                {
                                    // заносим очередной фмотив
                                    chain.FmotivList.Add((Fmotiv)dividedSameDuration[i].Clone());

                                    // присваиваем очередной id
                                    chain.FmotivList[chain.FmotivList.Count - 1].Id = chain.FmotivList.Count - 1;
                                }

                                // в буфер заносим последний фмотив цепочки фмотивов нот с равнодлительностью
                                fmotivBuffer = (Fmotiv)dividedSameDuration[dividedSameDuration.Count - 1].Clone();

                                // добавляем сохраненную ноту с большой длительностью
                                for (int i = 0; i < fmotivBuffer2.NoteList.Count; i++)
                                {
                                    fmotivBuffer.NoteList.Add((ValueNote)fmotivBuffer2.NoteList[i].Clone());
                                }

                                // флаг комбинации
                                combination = true;

                                // флаг возрастающей последовательности, чтобы завершить фмотив - комбинация
                                growingDurationChain = true;

                                // убираем флаг для сбора равнодлительных нот
                                sameDurationChain = false;

                                // сохранили сколько нот/пауз входит в текущий буфер
                                n = fmotivBuffer.NoteList.Count;
                            }

                            // если длительность предпоследнего равна длительности последнего
                            if (TempExtractor(fmotivBuffer, ExtractNoteList(fmotivBuffer).Count - 2).Duration.Equals(TempExtractor(fmotivBuffer, ExtractNoteList(fmotivBuffer).Count - 1).Duration))
                            {
                                // записываем очередную ноты в фмотив с типом последовательность равнодлительных звуков
                                // (она уже записана, поэтому просто сохраняем число входящих в фмотив на данный момент нот/пауз)
                                // сохранили сколько нот/пауз входит в буфер
                                n = fmotivBuffer.NoteList.Count;
                            }

                            // если длительность предпоследнего больше длительности последнего
                            if (FifthTempComparator(fmotivBuffer))
                            {
                                var fmotivBuffer2 = new Fmotiv(string.Empty);

                                // помещаем в буффер2 последнюю собранную ноту - меньшей длительности чем все равнодлительные
                                int count = fmotivBuffer.NoteList.Count; // так как меняется в процессе
                                for (int i = n; i < count; i++)
                                {
                                    fmotivBuffer2.NoteList.Add((ValueNote)fmotivBuffer.NoteList[n].Clone());
                                    fmotivBuffer.NoteList.RemoveAt(n);
                                }

                                // отправляем последовательность равнодлительных звуков на анализ, получаем цепочку фмотивов и заносим их в выходную последовательность
                                foreach (Fmotiv fmotiv in DivideSameDurationNotes(fmotivBuffer))
                                {
                                    // заносим очередной фмотив
                                    chain.FmotivList.Add((Fmotiv)fmotiv.Clone());

                                    // присваиваем очередной id
                                    chain.FmotivList[chain.FmotivList.Count - 1].Id = chain.FmotivList.Count - 1;
                                }

                                // очищаем буффер
                                fmotivBuffer.NoteList.Clear();

                                // добавляем состав сохраненной ноты (паузы/лиги) с меньшей длительностью в буфер
                                for (int i = 0; i < fmotivBuffer2.NoteList.Count; i++)
                                {
                                    fmotivBuffer.NoteList.Add((ValueNote)fmotivBuffer2.NoteList[i].Clone());
                                }

                                // убираем флаг для сбора равнодлительных нот
                                sameDurationChain = false;

                                // сохранили сколько нот/пауз входит в текущий буфер
                                n = fmotivBuffer.NoteList.Count;
                            }
                        }
                        else
                        {
                            if (growingDurationChain)
                            {
                                // если длительность предпоследнего меньше длительности последнего
                                if (ForthTempComparator(fmotivBuffer))
                                {
                                    // записываем очередную ноты в фмотив с типом возрастающая последовательность
                                    // (она уже записана, поэтому просто сохраняем число входящих в фмотив на данный момент нот)
                                    n = fmotivBuffer.NoteList.Count; // сохранили сколько нот/пауз входит в буфер
                                }
                                else
                                {
                                    // иначе если длительности равны, или последняя по длительности меньше предпоследней, то составляем новый фмотив
                                    // также сохраняем не вошедшую последнюю ноту (не удаляем ее)
                                    if (combination)
                                    {
                                        var fm = new Fmotiv(fmotivBuffer.Type + "ВП", chain.FmotivList.Count);

                                        // ЧМТВП или ПМТВП
                                        for (int i = 0; i < n; i++)
                                        {
                                            // заносим
                                            fm.NoteList.Add((ValueNote)fmotivBuffer.NoteList[0].Clone());

                                            // удаляем
                                            fmotivBuffer.NoteList.RemoveAt(0);
                                        }

                                        // добавляем в выходную цепочку получившийся фмотив
                                        chain.FmotivList.Add((Fmotiv)fm.Clone());

                                        // сохранили сколько нот/пауз осталось в буфере от последней не вошедшей в фмотив ноты
                                        n = fmotivBuffer.NoteList.Count;

                                        // убрали флаг сбора возрастающей последовательности
                                        growingDurationChain = false;

                                        // убрали флаг сбора возрастающей последовательности
                                        combination = false;
                                    }
                                    else
                                    {
                                        var fm = new Fmotiv("ВП", chain.FmotivList.Count);
                                        for (int i = 0; i < n; i++)
                                        {
                                            // заносим
                                            fm.NoteList.Add((ValueNote)fmotivBuffer.NoteList[0].Clone());

                                            // удаляем
                                            fmotivBuffer.NoteList.RemoveAt(0);
                                        }

                                        // добавляем в выходную цепочку получившийся фмотив
                                        chain.FmotivList.Add((Fmotiv)fm.Clone());

                                        // сохранили сколько нот/пауз осталось в буфере от последней не вошедшей в фмотив ноты
                                        n = fmotivBuffer.NoteList.Count;

                                        // убрали флаг сбора возрастающей последовательности
                                        growingDurationChain = false;
                                    }
                                }
                            }
                        }
                    }
                }
            }

            // если в буфере осталась 1 непроанализированная нота
            if (ExtractNoteList(fmotivBuffer).Count == 1)
            {
                // заносим ноты/паузы 1 собранной ноты в очередной фмотив с типом ЧМТ, и удаляем из буфера
                var fm = new Fmotiv("ЧМТ", chain.FmotivList.Count);

                // for (int i = 0; i < FmotivBuffer.NoteList.Count; i++)
                foreach (ValueNote note in fmotivBuffer.NoteList)
                {
                    // заносим
                    fm.NoteList.Add((ValueNote)note.Clone());
                }

                // добавляем в выходную цепочку получившийся фмотив
                chain.FmotivList.Add((Fmotiv)fm.Clone());

                // очищаем буффер
                fmotivBuffer.NoteList.Clear();
            }

            // если в буфере остались непроанализированные ноты (больше 1)
            if (ExtractNoteList(fmotivBuffer).Count > 1)
            {
                if (sameDurationChain)
                {
                    // отправляем последовательность равнодлительных звуков на анализ, получаем цепочку фмотивов и заносим их в выходную последовательность
                    foreach (Fmotiv fmotiv in DivideSameDurationNotes(fmotivBuffer))
                    {
                        // заносим очередной фмотив
                        chain.FmotivList.Add((Fmotiv)fmotiv.Clone());

                        // присваиваем очередной id
                        chain.FmotivList[chain.FmotivList.Count - 1].Id = chain.FmotivList.Count - 1;
                    }

                    // очищаем буффер
                    fmotivBuffer.NoteList.Clear();
                }
                else
                {
                    if (growingDurationChain)
                    {
                        if (combination)
                        {
                            // заносим оставшиеся ноты в комбинированный фмотив ЧМТ/ПМТ + ВП и в выходную цепочку
                            var fm = new Fmotiv(fmotivBuffer.Type + "ВП", chain.FmotivList.Count); // ЧМТВП или ПМТВП
                            foreach (ValueNote note in fmotivBuffer.NoteList)
                            {
                                // заносим
                                fm.NoteList.Add((ValueNote)note.Clone());
                            }

                            // добавляем в выходную цепочку получившийся фмотив
                            chain.FmotivList.Add((Fmotiv)fm.Clone());

                            // очищаем буффер
                            fmotivBuffer.NoteList.Clear();
                        }
                        else
                        {
                            // заносим оставшиеся ноты в фмотив ВП и в выходную цепочку
                            var fm = new Fmotiv("ВП", chain.FmotivList.Count);
                            foreach (ValueNote note in fmotivBuffer.NoteList)
                            {
                                // заносим
                                fm.NoteList.Add((ValueNote)note.Clone());
                            }

                            // добавляем в выходную цепочку получившийся фмотив
                            chain.FmotivList.Add((Fmotiv)fm.Clone());

                            // очищаем буффер
                            fmotivBuffer.NoteList.Clear();
                        }
                    }
                }
            }

            return chain;
        }
        public void MeasureOrderTest()
        {
            // создание и заполнения списка(ов) нот для такта(ов) монотрека
            var notes = new List<ValueNote>
            {
                new ValueNote(new Pitch(3, 'A', 2), new Duration(1, 16, false, 128), false, Tie.None, 3),
                new ValueNote(new Pitch(3, 'E', 0), new Duration(1, 4, false, 512), false, Tie.None, 0),
                new ValueNote(new Pitch(3, 'E', 0), new Duration(1, 4, false, 512), false, Tie.None, 0),
                new ValueNote(new Pitch(3, 'C', 1), new Duration(1, 16, false, 128), false, Tie.None, 1)
            };

            var notes3 = new List<ValueNote>
            {
                new ValueNote(new Pitch(3, 'B', 0), new Duration(1, 16, false, 128), false, Tie.None, 3),
                new ValueNote(new Pitch(3, 'E', 0), new Duration(1, 4, false, 512), false, Tie.None, 0),
                new ValueNote(new Pitch(3, 'E', 0), new Duration(1, 4, false, 512), false, Tie.None, 0),
                new ValueNote(new Pitch(3, 'C', 1), new Duration(1, 16, false, 128), false, Tie.None, 1)
            };

            var notes2 = new List<ValueNote>
            {
                new ValueNote(new Pitch(3, 'B', 0), new Duration(1, 16, false, 128), false, Tie.None, 1),
                new ValueNote(new Pitch(3, 'A', 2), new Duration(1, 16, false, 128), false, Tie.None, 3),
                new ValueNote(new Pitch(3, 'E', 0), new Duration(1, 4, false, 512), false, Tie.None, 0),
                new ValueNote(new Pitch(3, 'E', 0), new Duration(1, 4, false, 512), false, Tie.None, 0),
                new ValueNote(new Pitch(3, 'C', 1), new Duration(1, 16, false, 128), false, Tie.None, 1)
            };

            var notes4 = new List<ValueNote>
            {
                new ValueNote(new Pitch(3, 'A', -1), new Duration(1, 16, false, 128), false, Tie.None, 3),
                new ValueNote(new Pitch(3, 'D', 0), new Duration(1, 4, false, 128), false, Tie.None, 2),
                new ValueNote(new Pitch(3, 'A', 2), new Duration(1, 16, false, 128), false, Tie.None, 3),
                new ValueNote(new Pitch(3, 'C', 1), new Duration(1, 4, false, 128), false, Tie.None, 1)
            };

            var notes5 = new List<ValueNote>
            {
                new ValueNote((Pitch)null, new Duration(1, 4, false, 128), false, Tie.None, 1),
                new ValueNote((Pitch)null, new Duration(1, 4, false, 128), false, Tie.None, 1)
            };

            var notes6 = new List<ValueNote>
            {
                new ValueNote((Pitch)null, new Duration(1, 16, false, 128), false, Tie.None, 1),
                new ValueNote((Pitch)null, new Duration(1, 16, false, 128), false, Tie.None, 1)
            };

            var attr = new Attributes(new Size(4, 4, 128), new Key(5));

            var m1 = new Measure(notes, attr);
            var m2 = new Measure(notes2, attr);
            var m3 = new Measure(notes3, attr);
            var m4 = new Measure(notes4, attr);
            var m5 = new Measure(notes5, attr);
            var m6 = new Measure(notes6, attr);

            var measuresList = new List<Measure> { m1, m2, m3, m4, m5, m5, m2, m3, m6 };

            var uni = new CongenericScoreTrack("a1", measuresList);

            Assert.AreEqual(uni.MeasureOrder()[0].Id, 0);
            Assert.AreEqual(uni.MeasureOrder()[1].Id, 1);
            Assert.AreEqual(uni.MeasureOrder()[2].Id, 0);
            Assert.AreEqual(uni.MeasureOrder()[3].Id, 2);
            Assert.AreEqual(uni.MeasureOrder()[4].Id, 3);
            Assert.AreEqual(uni.MeasureOrder()[5].Id, 3);
            Assert.AreEqual(uni.MeasureOrder()[6].Id, 1);
            Assert.AreEqual(uni.MeasureOrder()[7].Id, 0);
            Assert.AreEqual(uni.MeasureOrder()[8].Id, 4);

            Assert.AreEqual(uni.MeasureIdOrder()[0], 0);
            Assert.AreEqual(uni.MeasureIdOrder()[1], 1);
            Assert.AreEqual(uni.MeasureIdOrder()[2], 0);
            Assert.AreEqual(uni.MeasureIdOrder()[3], 2);
            Assert.AreEqual(uni.MeasureIdOrder()[4], 3);
            Assert.AreEqual(uni.MeasureIdOrder()[5], 3);
            Assert.AreEqual(uni.MeasureIdOrder()[6], 1);
            Assert.AreEqual(uni.MeasureIdOrder()[7], 0);
            Assert.AreEqual(uni.MeasureIdOrder()[8], 4);
        }
        public void ValueNoteOrderSecondTest()
        {
            // создание и заполнения списка(ов) нот для такта(ов) монотрека
            var notes = new List<ValueNote>
            {
                new ValueNote(new Pitch(3, 'A', 2), new Duration(1, 16, false, 128), false, Tie.None, 3),
                new ValueNote(new Pitch(3, 'E', 0), new Duration(1, 4, false, 512), false, Tie.None, 0),
                new ValueNote(new Pitch(3, 'E', 0), new Duration(1, 4, false, 512), false, Tie.None, 0),
                new ValueNote(new Pitch(3, 'C', 1), new Duration(1, 16, false, 128), false, Tie.None, 1),
                new ValueNote(new Pitch(3, 'A', -1), new Duration(1, 16, false, 128), false, Tie.None, 3),
                new ValueNote(new Pitch(3, 'D', 0), new Duration(1, 16, false, 128), false, Tie.None, 2),
                new ValueNote(new Pitch(3, 'A', 2), new Duration(1, 16, false, 128), false, Tie.None, 3),
                new ValueNote(new Pitch(3, 'C', 1), new Duration(1, 16, false, 128), false, Tie.None, 1),
                new ValueNote(new Pitch(3, 'C', 1), new Duration(1, 16, false, 128), false, Tie.None, 1)
            };

            var notes2 = new List<ValueNote>
            {
                new ValueNote(new Pitch(3, 'B', 0), new Duration(1, 16, false, 128), false, Tie.None, 1),
                new ValueNote(new Pitch(3, 'A', 2), new Duration(1, 16, false, 128), false, Tie.None, 3),
                new ValueNote(new Pitch(3, 'E', 0), new Duration(1, 4, false, 512), false, Tie.None, 0),
                new ValueNote(new Pitch(3, 'E', 0), new Duration(1, 4, false, 512), false, Tie.None, 0),
                new ValueNote(new Pitch(3, 'C', 1), new Duration(1, 16, false, 128), false, Tie.None, 1),
                new ValueNote(new Pitch(3, 'A', -1), new Duration(1, 16, false, 128), false, Tie.None, 3),
                new ValueNote(new Pitch(3, 'D', 0), new Duration(1, 4, false, 128), false, Tie.None, 2),
                new ValueNote(new Pitch(3, 'A', 2), new Duration(1, 16, false, 128), false, Tie.None, 3),
                new ValueNote(new Pitch(3, 'C', 1), new Duration(1, 4, false, 128), false, Tie.None, 1),
                new ValueNote((Pitch)null, new Duration(1, 4, false, 128), false, Tie.None, 1),
                new ValueNote((Pitch)null, new Duration(1, 4, false, 128), false, Tie.None, 1),
                new ValueNote((Pitch)null, new Duration(1, 16, false, 128), false, Tie.None, 1),
                new ValueNote((Pitch)null, new Duration(1, 16, false, 128), false, Tie.None, 1)
            };

            var attr = new Attributes(new Size(4, 4), new Key(5));

            var m1 = new Measure(notes, attr);
            var m2 = new Measure(notes2, attr);

            var mlist = new List<Measure> { m1, m2 };

            var uni = new CongenericScoreTrack("a1", mlist);

            Assert.AreNotEqual(uni.NoteIdOrder()[0], 1);

            Assert.AreEqual(uni.NoteIdOrder()[0], 0);
            Assert.AreEqual(uni.NoteIdOrder()[1], 1);
            Assert.AreEqual(uni.NoteIdOrder()[2], 1);

            Assert.AreEqual(uni.NoteIdOrder()[3], 2);
            Assert.AreEqual(uni.NoteIdOrder()[4], 3);
            Assert.AreEqual(uni.NoteIdOrder()[5], 4);

            Assert.AreEqual(uni.NoteIdOrder()[6], 0);
            Assert.AreEqual(uni.NoteIdOrder()[7], 2);
            Assert.AreEqual(uni.NoteIdOrder()[8], 2);

            Assert.AreEqual(uni.NoteIdOrder()[9], 0);
            Assert.AreEqual(uni.NoteIdOrder()[10], 0);
            Assert.AreEqual(uni.NoteIdOrder()[11], 1);

            Assert.AreEqual(uni.NoteIdOrder()[12], 1);
            Assert.AreEqual(uni.NoteIdOrder()[13], 2);
            Assert.AreEqual(uni.NoteIdOrder()[14], 3);

            Assert.AreEqual(uni.NoteIdOrder()[15], 5);
            Assert.AreEqual(uni.NoteIdOrder()[16], 0);
            Assert.AreEqual(uni.NoteIdOrder()[17], 6);

            Assert.AreEqual(uni.NoteIdOrder()[18], 7);
            Assert.AreEqual(uni.NoteIdOrder()[19], 7);
            Assert.AreEqual(uni.NoteIdOrder()[20], 8);
            Assert.AreEqual(uni.NoteIdOrder()[21], 8);
        }
 /// <summary>
 /// The convert congeneric score track to base chain.
 /// </summary>
 /// <param name="scoreTrack">
 /// The score track.
 /// </param>
 /// <returns>
 /// The <see cref="BaseChain"/>.
 /// </returns>
 private BaseChain ConvertCongenericScoreTrackToBaseChain(CongenericScoreTrack scoreTrack)
 {
     var notes = scoreTrack.GetNotes();
     return new BaseChain(((IEnumerable<IBaseObject>)notes).ToList());
 }