The measure.
Inheritance: IBaseObject
        public void MeasureFirstTest()
        {
            var notes = new List<ValueNote>();
            var notes2 = new List<ValueNote>();
            var attributes = new Attributes(new Size(4, 4, 512), new Key(5));

            notes.Add(new ValueNote(new Pitch(3, 'A', 0), new Duration(1, 4, false, 128), false, Tie.None));
            notes.Add(new ValueNote(new Pitch(3, 'B', 0), new Duration(1, 4, false, 128), false, Tie.None));
            notes.Add(new ValueNote(new Pitch(3, 'C', 0), new Duration(1, 16, false, 32), false, Tie.None));

            notes2.Add(new ValueNote(new Pitch(3, 'A', 0), new Duration(1, 4, false, 128), false, Tie.None));
            notes2.Add(new ValueNote(new Pitch(3, 'B', 0), new Duration(1, 4, false, 128), false, Tie.None));
            notes2.Add(new ValueNote(new Pitch(3, 'C', 0), new Duration(1, 16, false, 32), false, Tie.None));

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

            Assert.IsTrue(m1.Equals(m2));
        }
        /// <summary>
        /// The calculate.
        /// </summary>
        /// <param name="measure">
        /// The measure.
        /// </param>
        /// <exception cref="Exception">
        /// Thrown in different cases.
        /// </exception>
        public void Calculate(Measure measure)
        {
            // создаем новый такт, куда будут складываться ноты, после определения их приоритета.
            var temp = new Measure(new List<ValueNote>(), (Attributes)measure.Attributes.Clone());

            // считаем маску приоритетов для такта
            CalculatePriorityMask(measure);

            // соотнесение маски приоритетов и реального такта
            double bufDuration = 0;

            // буфер длительности
            var noteBuf = new List<ValueNote>();

            // буфер нот для сбора триоли и передачи в CollectTriplet
            var maskBuf = new List<ValueNote>();

            // буфер маски приоритетов для сбора приоритетов маски под триолью и передачи в CollectTriplet
            double tripletDuration = 0;

            // для каждой ноты подсчет приоритета, либо собирание в триоль и отдельный подсчет приоритетов
            foreach (ValueNote note in measure.NoteList)
            {
                if (note.Triplet)
                {
                    // если идет две триоли подряд, то как только первая сменяет вторую - меняется размер длительности у след. ноты
                    // и как только это произошло, нужно сначала проанализировать первую триоль и потом начать заполнять вторую
                    if ((note.Duration.Value != tripletDuration) && (noteBuf.Count > 0))
                    {
                        while (bufDuration > 0.0000001)
                        {
                            // собираем буфер маски приоритетов для триоли,
                            // собираем пока суммарная длительность нот маски не превышает длительность реальных нот триоли
                            maskBuf.Add((ValueNote)PriorityMask.NoteList[0].Clone());
                            bufDuration = bufDuration - PriorityMask.NoteList[0].Duration.Value;
                            PriorityMask.NoteList.RemoveAt(0);
                        }

                        // передача методу CountTriplet notebuf + maskbuf и расстановка приоритетов + передача обратно
                        // занесение в выходной буфер результата определения приоритета нот триоли
                        foreach (ValueNote tnote in CountTripletPriority(noteBuf, maskBuf))
                        {
                            temp.NoteList.Add((ValueNote)tnote.Clone());
                        }

                        // Temp.Notelist.AddRange(CountTripletPriority(noteBuf,maskBuf));

                        // зануление буферов
                        noteBuf.Clear();
                        maskBuf.Clear();
                        bufDuration = 0;
                    }

                    // последовательность реальных нот триоли (триплета) заносится в буфер для дальнейшей обработки
                    // считается суммарная длительность триоли
                    noteBuf.Add((ValueNote)note.Clone());
                    tripletDuration = note.Duration.Value;

                    // сохраняем размерность триоли/ новой триоли (если две подряд)
                    bufDuration = bufDuration + note.Duration.Value;
                }
                else
                {
                    // если следущая нота не триоль, то проверка, собиралась ли она шагом ранее, если да то вызов метода CollectTriplet,
                    if (noteBuf.Count > 0)
                    {
                        while (bufDuration > 0.0000001)
                        {
                            // собираем буфер маски приоритетов для триоли,
                            // собираем пока суммарная длительность нот маски не превышает длительность реальных нот триоли
                            maskBuf.Add((ValueNote)PriorityMask.NoteList[0].Clone());
                            bufDuration = bufDuration - PriorityMask.NoteList[0].Duration.Value;
                            PriorityMask.NoteList.RemoveAt(0);
                        }

                        // передача методу CountTriplet notebuf + maskbuf и расстановка приоритетов + передача обратно
                        // занесение в выходной буфер результата определения приоритета нот триоли
                        foreach (ValueNote tnote in CountTripletPriority(noteBuf, maskBuf))
                        {
                            temp.NoteList.Add((ValueNote)tnote.Clone());
                        }

                        // Temp.Notelist.AddRange(CountTripletPriority(noteBuf,maskBuf));

                        // зануление буферов
                        noteBuf.Clear();
                        maskBuf.Clear();
                    }

                    // так как следущая нота не триплет, то определяем ее приоритет по следущему алгоритму
                    // присвоение приоритета при нахожении начала позиции следущей ноты в маске приоритетов
                    note.Priority = PriorityMask.NoteList[0].Priority;

                    // занесение в буфер длительности следующей ноты маски приоритетов
                    bufDuration = PriorityMask.NoteList[0].Duration.Value;

                    // удаление этой ноты из общей маски приоритетов
                    PriorityMask.NoteList.RemoveAt(0);

                    // цикл, если набралось в буфер нот общей длительностью равной реальной ноте, то переходим к следующей реальной ноте
                    while ((note.Duration.Value - bufDuration) > 0.0000001)
                    {
                        if (PriorityMask.NoteList.Count < 1)
                        {
                            throw new Exception("LibiadaMusic Priority Discover: такт построен не по правилам, не хватает ноты");
                        }

                        // набор длительностей нот маски, и их удаление из очереди
                        bufDuration = bufDuration + PriorityMask.NoteList[0].Duration.Value;
                        PriorityMask.NoteList.RemoveAt(0);
                    }

                    // переход к следующей реальной ноте
                    temp.NoteList.Add((ValueNote)note.Clone());
                    bufDuration = bufDuration - note.Duration.Value;
                }
            }

            // проверка буфера триоли, на случай когда триоль стоит вконце, чтобы не было потери нот
            if (noteBuf.Count > 0)
            {
                while (bufDuration > 0.0000001)
                {
                    // собираем буфер маски приоритетов для триоли,
                    // собираем пока суммарная длительность нот маски не превышает длительность реальных нот триоли
                    maskBuf.Add((ValueNote)PriorityMask.NoteList[0].Clone());
                    bufDuration = bufDuration - PriorityMask.NoteList[0].Duration.Value;
                    PriorityMask.NoteList.RemoveAt(0);
                }

                // передача методу CountTriplet notebuf + maskbuf и расстановка приоритетов + передача обратно
                // занесение в выходной буфер результата определения приоритета нот триоли
                foreach (ValueNote tnote in CountTripletPriority(noteBuf, maskBuf))
                {
                    temp.NoteList.Add((ValueNote)tnote.Clone());
                }

                // зануление буферов
                noteBuf.Clear();
                maskBuf.Clear();
            }

            // присваиваем полю приоритет входного объекта, вычисленный приоритет в Temp соответственно
            for (int i = 0; i < measure.NoteList.Count; i++)
            {
                measure.NoteList[i].Priority = temp.NoteList[i].Priority;
                if (measure.NoteList[i].Priority < 0)
                {
                    throw new Exception("LibiadaMusic.PriorityDiscover: не выявлен приоритет для одной из нот (равен -1)");
                }
            }
        }
        /// <summary>
        /// The min duration.
        /// </summary>
        /// <param name="measure">
        /// The measure.
        /// </param>
        /// <returns>
        /// The <see cref="double"/>.
        /// </returns>
        /// <exception cref="Exception">
        /// Thrown if measure contains no notes.
        /// </exception>
        public double MinDuration(Measure measure)
        {
            // Метод находит минимальную длительность ноты/паузы в такте
            double value = 0;
            if (measure.NoteList.Count > 0)
            {
                value = measure.NoteList[0].Duration.Value;
            }
            else
            {
                // заносим в буфер первый элемент массива длительностей нот, если такт пустой - ошибка!
                throw new Exception("LibiadaMusic.OIP: обнаружен пустой такт при выявлении приоритета!");
            }

            foreach (ValueNote note in measure.NoteList)
            {
                if (value > note.Duration.Value)
                {
                    value = note.Duration.Value;
                }
            }

            return value;
        }
        /// <summary>
        /// Calculate priority mask method.
        /// </summary>
        /// <param name="measure">
        /// The measure.
        /// </param>
        public void CalculatePriorityMask(Measure measure)
        {
            // создание объекта маски с атрибутами оригинала и пустым списком нот
            PriorityMask = new Measure(new List<ValueNote>(), (Attributes)measure.Attributes.Clone());

            //---------------------------Занесение начальных долей размера такта---------------------------
            //---------------------------------------------------------------------------------------------
            var newDuration = new Duration(1, measure.Attributes.Size.BeatBase, false, measure.Attributes.Size.TicksPerBeat);

            PriorityMask.NoteList.Add(new ValueNote((Pitch)null, newDuration, false, Tie.None, 0));

            // первая доля в такте всегда самая сильная и выделяется НАИВЫСШИМ приоритетом 0
            if (measure.Attributes.Size.Beats % 2 == 0)
            {
                // ПМТ-2 - двудольный метр/размер такта
                for (int i = 1; i < measure.Attributes.Size.Beats; i++)
                {
                    // начиная со второй доли заполняем чередуя приоритет через одну долю
                    if (i % 2 == 0)
                    {
                        // относительно сильная доля с приоритетом 1
                        const int Priority = 1;
                        var duration = new Duration(1, measure.Attributes.Size.BeatBase, false, measure.Attributes.Size.TicksPerBeat);
                        PriorityMask.NoteList.Add(new ValueNote((Pitch)null, duration, false, Tie.None, Priority));
                    }
                    else
                    {
                        // слабая доля с приоритетом 2
                        int priority = 2;

                        // если всего две доли то более слабая будет иметь приоритет 1, так как больше нет долей
                        if (measure.Attributes.Size.Beats == 2)
                        {
                            priority = 1;
                        }

                        var duration = new Duration(1, measure.Attributes.Size.BeatBase, false, measure.Attributes.Size.TicksPerBeat);
                        PriorityMask.NoteList.Add(new ValueNote((Pitch)null, duration, false, Tie.None, priority));
                    }
                }
            }
            else
            {
                if (measure.Attributes.Size.Beats % 3 == 0)
                {
                    // ПМТ-3 - трёхдольный метр/размер такта
                    for (int i = 1; i < measure.Attributes.Size.Beats; i++)
                    {
                        // начиная со второй доли заполняем чередуя приоритет через две доли
                        if (i % 3 == 0)
                        {
                            // относительно сильная доля с приоритетом 1
                            int priority = 1;
                            var duration = new Duration(1, measure.Attributes.Size.BeatBase, false, measure.Attributes.Size.TicksPerBeat);
                            PriorityMask.NoteList.Add(new ValueNote((Pitch)null, duration, false, Tie.None, priority));
                        }
                        else
                        {
                            // слабая доля с приоритетом 2
                            int priority = 2;

                            // если всего три доли то более слабые будут иметь приоритет 1, так как больше нет других долей
                            if (measure.Attributes.Size.Beats == 3)
                            {
                                priority = 1;
                            }

                            var duration = new Duration(1, measure.Attributes.Size.BeatBase, false, measure.Attributes.Size.TicksPerBeat);
                            PriorityMask.NoteList.Add(new ValueNote((Pitch)null, duration, false, Tie.None, priority));
                        }
                    }
                }
                else
                {
                    // ПМТ-К сложный метр/размер такта
                    for (int i = 1; i < measure.Attributes.Size.Beats; i++)
                    {
                        // начиная со второй доли заполняем чередуя приоритет через
                        // одну долю и последнюю долю записываем как слабую
                        if (i % 2 == 0)
                        {
                            // относительно сильная доля с приоритетом 1
                            int priority = 1;

                            // если сильная доля последняя - записываем ее как слабую в ПМТ-3
                            if (i == measure.Attributes.Size.Beats - 1)
                            {
                                priority = 2;
                            }

                            var duration = new Duration(1, measure.Attributes.Size.BeatBase, false, measure.Attributes.Size.TicksPerBeat);
                            PriorityMask.NoteList.Add(new ValueNote((Pitch)null, duration, false, Tie.None, priority));
                        }
                        else
                        {
                            // слабая доля с приоритетом 2
                            const int Priority = 2;
                            var duration = new Duration(1, measure.Attributes.Size.BeatBase, false, measure.Attributes.Size.TicksPerBeat);
                            PriorityMask.NoteList.Add(new ValueNote((Pitch)null, duration, false, Tie.None, Priority));
                        }
                    }
                }
            }

            //---------------------------Разложение долей такта на более низкий уровень, ---------------------------
            //---------------------------пока не будут известны приоритеты для нот с минимальной длительностью------
            //------------------------------------------------------------------------------------------------------

            // флаг останова, когда просчитаются приоритеты для всех нот,
            // длительность которых окажется меньше либо равна минимальной, деленной на 2 (так как может быть точка у ноты, котору. возможно описать только 3 нотами короче в два раза чем сама нота),
            // если они уже просчитаны для всех нот, то процесс заканчивается
            bool stop = true;

            // проверка: останов будет тогда, когда длительности ВСЕХ нот в маске будут меньше либо равны длительности минимально ноты
            foreach (ValueNote note in PriorityMask.NoteList)
            {
                if (note.Duration.Value > MinDuration(measure) / 2)
                {
                    stop = false;
                }
            }

            while (!stop)
            {
                var temp = new Measure(new List<ValueNote>(), (Attributes)PriorityMask.Attributes.Clone());

                // создание объекта буфера для перехода к следущей маске нижнего уровня

                // определение максимального (наименьшего приоритета) для спуска на уровень ниже,
                // где появятся ноты с приоритетом еще ниже на 1 ( +1)
                int maxPriority = 0;
                foreach (ValueNote note in PriorityMask.NoteList)
                {
                    if (maxPriority < note.Priority)
                    {
                        maxPriority = note.Priority;
                    }
                }

                for (int i = 0; i < PriorityMask.NoteList.Count; i++)
                {
                    var duration = new Duration(1, PriorityMask.NoteList[i].Duration.Denominator * 2, false, PriorityMask.NoteList[i].Duration.Ticks / 2);

                    temp.NoteList.Add(new ValueNote((Pitch)null, duration, false, Tie.None, PriorityMask.NoteList[i].Priority));

                    duration = new Duration(1, PriorityMask.NoteList[i].Duration.Denominator * 2, false, PriorityMask.NoteList[i].Duration.Ticks / 2);

                    temp.NoteList.Add(new ValueNote((Pitch)null, duration, false, Tie.None, maxPriority + 1));
                }

                // присваем объекту маске новый получившейся объект уровня ниже
                PriorityMask = (Measure)temp.Clone();

                // высталение флага останова
                stop = true;

                // проверка: останов будет тогда, когда длительности ВСЕХ нот в маске будут меньше либо равны длительности минимальной ноты
                // деленной на два (смотри выше из-за точки)
                foreach (ValueNote note in PriorityMask.NoteList)
                {
                    if (note.Duration.Value > MinDuration(measure) / 2)
                    {
                        stop = false;
                    }
                }
            }
        }
        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 clone.
 /// </summary>
 /// <returns>
 /// The <see cref="IBaseObject"/>.
 /// </returns>
 public IBaseObject Clone()
 {
     var temp = new Measure(NoteList, Attributes);
     return temp;
 }
        /// <summary>
        /// The merge measures.
        /// </summary>
        /// <param name="measure">
        /// The measure.
        /// </param>
        public void MergeMeasures(Measure measure)
        {
            int k = 0;

            // проведём цикл до тех пор, пока номер текущей ноты не превышает количество нот в обоих тактах
            while ((k < NoteList.Count) && (k < measure.NoteList.Count))
            {
                if (NoteList[k].Duration.Equals(measure.NoteList[k].Duration))
                {
                    // ноты одинаковы по длине, можно просто склеить
                    NoteList[k].AddPitch(measure.NoteList[k].Pitch);
                }
                else
                {
                    var tempNoteList = new List<ValueNote>(0);
                    if (NoteList[k].Duration.Value < measure.NoteList[k].Duration.Value)
                    {
                        // нота из склеенного массива короче, значит нужно вторую разделить на две и склеить
                        tempNoteList.AddRange(measure.NoteList[k].SplitNote(NoteList[k].Duration));
                        measure.NoteList.RemoveAt(k);
                        measure.NoteList.InsertRange(k, tempNoteList);
                        NoteList[k].AddPitch(measure.NoteList[k].Pitch);
                    }
                    else
                    {
                        // нота из склеенного массива длиннее, значит надо её делить и клеить со второй
                        tempNoteList.AddRange(NoteList[k].SplitNote(measure.NoteList[k].Duration));
                        NoteList.RemoveAt(k);
                        NoteList.InsertRange(k, tempNoteList);
                        NoteList[k].AddPitch(measure.NoteList[k].Pitch);
                    }
                }

                k++;
            }

            // теоретически на этом моменте у нас все ноты должны быть обработаны
            // хотя могло получиться, что в каком-то из тактов остались несклеенные ноты
        }
        public void PriorityDiscoverTest()
        {
            var notes = new List<ValueNote> { note, bnote, anote };
            var notes1 = new List<ValueNote> { note, note, note };
            var notes2 = new List<ValueNote> { anote, note, bnote, note, bnote };
            var notes3 = new List<ValueNote> { note, dnote, note, note };
            var notes4 = new List<ValueNote> { сnote, сnote, сnote, ccnote, ccnote, ccnote };
            var notes5 = new List<ValueNote> { сccnote, сccnote, сccnote, сccnote, сccnote, сccnote, сccnote, note, note };

            var measure = new Measure(notes, attributes);
            var measure1 = new Measure(notes1, attributes1);
            var measure2 = new Measure(notes2, attributes2);
            var measure3 = new Measure(notes3, attributes3);
            var measure4 = new Measure(notes4, attributes1);
            var measure5 = new Measure(notes5, attributes);

            var prioritydiscover = new PriorityDiscover();

            Assert.AreEqual(-1, measure.NoteList[0].Priority);
            Assert.AreEqual(-1, measure.NoteList[1].Priority);
            Assert.AreEqual(-1, measure.NoteList[2].Priority);

            prioritydiscover.Calculate(measure);
            prioritydiscover.Calculate(measure1);
            prioritydiscover.Calculate(measure2);
            prioritydiscover.Calculate(measure3);
            prioritydiscover.Calculate(measure4);
            prioritydiscover.Calculate(measure5);

            Assert.AreEqual(0, measure.NoteList[0].Priority);
            Assert.AreEqual(2, measure.NoteList[1].Priority);
            Assert.AreEqual(1, measure.NoteList[2].Priority);

            Assert.AreEqual(0, measure1.NoteList[0].Priority);
            Assert.AreEqual(1, measure1.NoteList[1].Priority);
            Assert.AreEqual(1, measure1.NoteList[2].Priority);

            Assert.AreEqual(0, measure2.NoteList[0].Priority);
            Assert.AreEqual(1, measure2.NoteList[1].Priority);
            Assert.AreEqual(1, measure2.NoteList[2].Priority);
            Assert.AreEqual(1, measure2.NoteList[3].Priority);
            Assert.AreEqual(1, measure2.NoteList[4].Priority);

            Assert.AreEqual(0, measure3.NoteList[0].Priority);
            Assert.AreEqual(1, measure3.NoteList[1].Priority);
            Assert.AreEqual(2, measure3.NoteList[2].Priority);
            Assert.AreEqual(2, measure3.NoteList[3].Priority);

            Assert.AreEqual(0, measure4.NoteList[0].Priority);
            Assert.AreEqual(1, measure4.NoteList[1].Priority);
            Assert.AreEqual(1, measure4.NoteList[2].Priority);
            Assert.AreEqual(1, measure4.NoteList[3].Priority);
            Assert.AreEqual(2, measure4.NoteList[4].Priority);
            Assert.AreEqual(2, measure4.NoteList[5].Priority);

            Assert.AreEqual(0, measure5.NoteList[0].Priority);
            Assert.AreEqual(3, measure5.NoteList[1].Priority);
            Assert.AreEqual(2, measure5.NoteList[2].Priority);
            Assert.AreEqual(3, measure5.NoteList[3].Priority);
            Assert.AreEqual(3, measure5.NoteList[4].Priority);
            Assert.AreEqual(3, measure5.NoteList[5].Priority);
            Assert.AreEqual(3, measure5.NoteList[6].Priority);
            Assert.AreEqual(1, measure5.NoteList[7].Priority);
            Assert.AreEqual(2, measure5.NoteList[8].Priority);

            Assert.AreEqual(-1, note.Priority);
            Assert.AreEqual(-1, bnote.Priority);
            Assert.AreEqual(-1, anote.Priority);
        }
        public void PriorityMinDurationTest()
        {
            var pd = new PriorityDiscover();

            var notes = new List<ValueNote> { note, bnote, dnote, anote };
            var measure = new Measure(notes, attributes);

            // минимальнвя длительность ноты в такте measure 1/16 = 0.0625 у ноты dnote
            Assert.IsTrue(Math.Abs(pd.MinDuration(measure) - 0.0625) < 0.00001);

            // когда такт передается пустой, должен выкинуться эксепшн
            measure.NoteList.Clear();
            try
            {
                Assert.IsTrue(Math.Abs(pd.MinDuration(measure) - 0.0625) < 0.00001);
                Assert.Fail("нет эксепшна при пустом такте");
            }
            catch (Exception e)
            {
                if (e.Message != "LibiadaMusic.OIP: обнаружен пустой такт при выявлении приоритета!")
                {
                    Assert.Fail();
                }
            }
        }
        public void PriorityMaskCalculationThirdTest()
        {
            var pd = new PriorityDiscover();

            var notes = new List<ValueNote> { note, bnote, dnote, anote };
            var measure = new Measure(notes, attributes3);
            pd.CalculatePriorityMask(measure);

            // так как минимальная длительность ноты в такте 1/16 то маска приоритетов должна разложиться (посчитаться) до 1/32
            // размер 13/16, поэтому будет считаться приоритет для 26/32 нот
            Assert.AreEqual(0, pd.PriorityMask.NoteList[0].Priority);
            Assert.AreEqual(3, pd.PriorityMask.NoteList[1].Priority);
            Assert.AreEqual(2, pd.PriorityMask.NoteList[2].Priority);
            Assert.AreEqual(3, pd.PriorityMask.NoteList[3].Priority);
            Assert.AreEqual(1, pd.PriorityMask.NoteList[4].Priority);
            Assert.AreEqual(3, pd.PriorityMask.NoteList[5].Priority);
            Assert.AreEqual(2, pd.PriorityMask.NoteList[6].Priority);
            Assert.AreEqual(3, pd.PriorityMask.NoteList[7].Priority);
            Assert.AreEqual(1, pd.PriorityMask.NoteList[8].Priority);
            Assert.AreEqual(3, pd.PriorityMask.NoteList[9].Priority);
            Assert.AreEqual(2, pd.PriorityMask.NoteList[10].Priority);
            Assert.AreEqual(3, pd.PriorityMask.NoteList[11].Priority);
            Assert.AreEqual(1, pd.PriorityMask.NoteList[12].Priority);
            Assert.AreEqual(3, pd.PriorityMask.NoteList[13].Priority);
            Assert.AreEqual(2, pd.PriorityMask.NoteList[14].Priority);
            Assert.AreEqual(3, pd.PriorityMask.NoteList[15].Priority);
            Assert.AreEqual(1, pd.PriorityMask.NoteList[16].Priority);
            Assert.AreEqual(3, pd.PriorityMask.NoteList[17].Priority);
            Assert.AreEqual(2, pd.PriorityMask.NoteList[18].Priority);
            Assert.AreEqual(3, pd.PriorityMask.NoteList[19].Priority);
            Assert.AreEqual(1, pd.PriorityMask.NoteList[20].Priority);
            Assert.AreEqual(3, pd.PriorityMask.NoteList[21].Priority);
            Assert.AreEqual(2, pd.PriorityMask.NoteList[22].Priority);
            Assert.AreEqual(3, pd.PriorityMask.NoteList[23].Priority);
            Assert.AreEqual(2, pd.PriorityMask.NoteList[24].Priority);
            Assert.AreEqual(3, pd.PriorityMask.NoteList[25].Priority);

            // проверка длительностей
            foreach (var lnote in pd.PriorityMask.NoteList)
            {
                Assert.AreEqual(1, lnote.Duration.Numerator);
                Assert.AreEqual(32, lnote.Duration.Denominator);
            }
        }
        public void PriorityMaskCalculationFourthTest()
        {
            var pd = new PriorityDiscover();

            var notes = new List<ValueNote> { note, anote };
            var measure = new Measure(notes, attributes1);
            pd.CalculatePriorityMask(measure);

            // так как минимальная длительность ноты в такте 1/4 то маска приоритетов должна разложиться (посчитаться) до 1/4
            // размер 3/4, поэтому будет считаться приоритет для 3/4 нот
            Assert.AreEqual(0, pd.PriorityMask.NoteList[0].Priority);
            Assert.AreEqual(2, pd.PriorityMask.NoteList[1].Priority);
            Assert.AreEqual(1, pd.PriorityMask.NoteList[2].Priority);
            Assert.AreEqual(2, pd.PriorityMask.NoteList[3].Priority);
            Assert.AreEqual(1, pd.PriorityMask.NoteList[4].Priority);
            Assert.AreEqual(2, pd.PriorityMask.NoteList[5].Priority);

            // проверка длительностей
            foreach (var lnote in pd.PriorityMask.NoteList)
            {
                Assert.AreEqual(1, lnote.Duration.Numerator);
                Assert.AreEqual(8, lnote.Duration.Denominator);
            }
        }