Beispiel #1
0
        private TrkDef GetF1Postlude(Palette f1PostludePalette, Krystal krystal, List <int> strandIndices, Dictionary <string, int> msPositions)
        {
            TrkDef f1p = f1PostludePalette.NewTrkDef(this.MidiChannel, krystal);

            List <int> f1eStrandDurations = GetStrandDurations(f1p, strandIndices);

            for (int i = f1p.Count - 1; i > 0; --i)
            {
                if (strandIndices.Contains(i))
                {
                    RestDef umrd = new RestDef(f1p[i].MsPosition, f1eStrandDurations[strandIndices.IndexOf(i)] / 4);
                    f1p.Insert(i, umrd);
                }
            }

            f1p.StartMsPosition = msPositions["postlude"];
            f1p.RemoveBetweenMsPositions(msPositions["endOfPiece"], int.MaxValue);

            return(f1p);
        }
Beispiel #2
0
        /// <summary>
        /// This function creates only one bar, but with VoiceDef objects.
        /// </summary>
        List <VoiceDef> CreateBar2(int bar2StartMsPos)
        {
            List <VoiceDef> bar = new List <VoiceDef>();

            byte          channel = 0;
            List <TrkDef> trkDefs = new List <TrkDef>();

            foreach (Palette palette in _palettes)
            {
                bar.Add(new TrkDef(channel, new List <IUniqueDef>()));
                TrkDef trkDef = palette.NewTrkDef(channel);
                trkDef.SetMsDuration(6000);
                trkDefs.Add(trkDef);
                ++channel;
            }
            int msPosition  = bar2StartMsPos;
            int maxBarMsPos = 0;

            for (int i = 0; i < trkDefs.Count; ++i)
            {
                int maxMsPos = WriteVoiceMidiDurationDefsInBar2(bar[i], trkDefs[i], msPosition, bar2StartMsPos);
                maxBarMsPos = maxBarMsPos > maxMsPos ? maxBarMsPos : maxMsPos;
                msPosition += 1500;
            }

            // now add the final rest in the bar
            for (int i = 0; i < trkDefs.Count; ++i)
            {
                int mdsdEndPos = trkDefs[i].EndMsPosition;
                if (maxBarMsPos > mdsdEndPos)
                {
                    RestDef rest2Def = new RestDef(mdsdEndPos, maxBarMsPos - mdsdEndPos);
                    bar[i].UniqueDefs.Add(rest2Def);
                }
            }
            return(bar);
        }
Beispiel #3
0
        /// <summary>
        /// ACHTUNG: could be a protected virtual function in a furies class
        /// </summary>
        private void Transform(TrkDef section, Dictionary <string, int> msPositions, List <int> strandIndices)
        {
            List <int> strandDurations = GetStrandDurations(section, strandIndices);

            int extraTime = 750;
            int diff      = extraTime / section.Count;

            for (int i = section.Count - 1; i > 0; --i)
            {
                if (strandIndices.Contains(i))
                {
                    RestDef umrd = new RestDef(section[i].MsPosition, strandDurations[strandIndices.IndexOf(i)] + extraTime);
                    extraTime -= diff;
                    section.Insert(i, umrd);
                }
            }

            section.StartMsPosition = msPositions["furies3FinaleStart"];

            #region old
            //double factor = 10;
            //section.AdjustMsDurations(factor);
            #endregion

            //section.CreateAccel(0, section.Count, 0.25);
            section.CreateAccel(0, section.Count, 0.13);

            //section.RemoveBetweenMsPositions(msPositions["interlude4End"], int.MaxValue);
            section.RemoveBetweenMsPositions(msPositions["finalWindChord"], int.MaxValue);

            if (section[section.Count - 1] is RestDef)
            {
                //section[section.Count - 1].MsDuration = msPositions["interlude4End"] - section[section.Count - 1].MsPosition;
                section[section.Count - 1].MsDuration = msPositions["endOfPiece"] - section[section.Count - 1].MsPosition;
            }
        }
Beispiel #4
0
        private void MidiEventDemoButton_Click(object sender, EventArgs e)
        {
            if (M.HasError(_allTextBoxes))
            {
                DoErrorMessage("Can't play because there is an error in one or more of the fields.");
            }
            else
            {
                Button       midiEventDemoButton = sender as Button;
                DurationDef  durationDef         = GetDurationDef();
                MidiChordDef midiChordDef        = durationDef as MidiChordDef;
                RestDef      restDef             = durationDef as RestDef;

                if (midiChordDef != null)
                {
                    int          midiChannel  = 0;
                    OutputDevice outputDevice = M.Preferences.CurrentMultimediaMidiOutputDevice;
                    if (_paletteForm.IsPercussionPalette)
                    {
                        midiChannel  = 9;
                        outputDevice = M.Preferences.GetMidiOutputDevice("Microsoft GS Wavetable Synth");
                    }
                    MidiChord midiChord = new MidiChord(midiChannel, midiChordDef, outputDevice);
                    midiChord.Send(); //sends in this thread (blocks the current thread -- keeping the button selected)
                }
                else
                {
                    midiEventDemoButton.Hide();
                    Refresh(); // shows "rest" behind button
                    Debug.Assert(restDef != null);
                    Thread.Sleep(restDef.MsDuration);
                    midiEventDemoButton.Show();
                    Refresh();
                }
            }
        }
Beispiel #5
0
        private void GetSnores(int firstRestMsDuration, Clytemnestra clytemnestra, TrkDef wind1, Palette snoresPalette)
        {
            List <IUniqueDef> snores = new List <IUniqueDef>();
            int msPosition           = 0;

            IUniqueDef firstRest = new RestDef(msPosition, firstRestMsDuration);

            snores.Add(firstRest);
            msPosition += firstRestMsDuration;

            #region prelude + verse1
            int[] transpositions1 = { 0, 0, 0, 0, 0, 1, 0 };
            for (int i = 0; i < 7; ++i)
            {
                IUniqueDef snore = snoresPalette.UniqueDurationDef(i);
                snore.MsPosition = msPosition;
                msPosition      += snore.MsDuration;
                MidiChordDef iumdd = snore as MidiChordDef;
                if (iumdd != null)
                {
                    iumdd.Transpose(transpositions1[i]);
                    iumdd.PitchWheelDeviation = 3;
                }
                snores.Add(snore);

                RestDef rest = new RestDef(msPosition, 2500);
                msPosition += rest.MsDuration;
                snores.Add(rest);
            }
            #endregion

            double   factor;
            double   msDuration;
            double   restDuration;
            int[]    transpositions2 = { 1, 1, 2, 2, 3, 3, 4, 4, 5, 5 };
            double[] factors         = { 0.93, 0.865, 0.804, 0.748, 0.696, 0.647, 0.602, 0.56, 0.52, 0.484 };
            for (int i = 0; i < 10; ++i)
            {
                IUniqueDef snore = snoresPalette.UniqueDurationDef(i / 2);
                snore.MsPosition = msPosition;
                factor           = factors[i];
                msDuration       = snore.MsDuration * factor;
                snore.MsDuration = (int)msDuration;
                msPosition      += snore.MsDuration;
                MidiChordDef iumdd = snore as MidiChordDef;
                if (iumdd != null)
                {
                    iumdd.Transpose(transpositions2[i]);
                    iumdd.PitchWheelDeviation = 20;
                }
                //iumdd.MidiVelocity = (byte)((double)snore.MidiVelocity * factor * factor);
                snores.Add(snore);

                restDuration = 2500 / factor;
                RestDef rest = new RestDef(msPosition, (int)restDuration);
                msPosition += rest.MsDuration;
                snores.Add(rest);
            }

            snores[snores.Count - 1].MsDuration = clytemnestra.EndMsPosition - snores[snores.Count - 1].MsPosition;

            this._uniqueDefs = snores;

            AdjustVelocitiesHairpin(13, Count, 0.25);

            #region alignments before Interlude3
            AlignObjectAtIndex(7, 8, 9, clytemnestra[3].MsPosition);
            AlignObjectAtIndex(8, 9, 10, clytemnestra[7].MsPosition);
            AlignObjectAtIndex(9, 10, 11, clytemnestra[16].MsPosition);
            AlignObjectAtIndex(10, 11, 12, clytemnestra[24].MsPosition);
            AlignObjectAtIndex(11, 12, 13, clytemnestra[39].MsPosition);
            AlignObjectAtIndex(12, 13, 14, clytemnestra[42].MsPosition);
            AlignObjectAtIndex(14, 34, Count, wind1[38].MsPosition); // rest at start of Interlude3
            #endregion

            RemoveScorePitchWheelCommands(0, 13); // pitchwheeldeviation is 20 for R2M
        }
Beispiel #6
0
        /// <summary>
        /// There is currently still one bar per system.
        /// Each voice ends with a barline.
        /// </summary>
        protected virtual void ReplaceConsecutiveRestsInBars(int minimumCrotchetDuration)
        {
            foreach (SvgSystem system in Systems)
            {
                foreach (Staff staff in system.Staves)
                {
                    if (!(staff is InvisibleOutputStaff))
                    {
                        foreach (Voice voice in staff.Voices)
                        {
                            Debug.Assert(voice.NoteObjects[voice.NoteObjects.Count - 1] is Barline);
                            // contains lists of consecutive rest indices
                            List <List <int> > restsToReplace = new List <List <int> >();
                            #region find the consecutive rests
                            List <int> consecRestIndices = new List <int>();
                            for (int i = 0; i < voice.NoteObjects.Count - 1; i++)
                            {
                                Debug.Assert(!(voice.NoteObjects[i] is Barline));

                                RestSymbol rest1 = voice.NoteObjects[i] as RestSymbol;
                                RestSymbol rest2 = voice.NoteObjects[i + 1] as RestSymbol;
                                if (rest1 != null && rest2 != null)
                                {
                                    if (!consecRestIndices.Contains(i))
                                    {
                                        consecRestIndices.Add(i);
                                    }
                                    consecRestIndices.Add(i + 1);
                                }
                                else
                                {
                                    if (consecRestIndices != null && consecRestIndices.Count > 0)
                                    {
                                        restsToReplace.Add(consecRestIndices);
                                        consecRestIndices = new List <int>();
                                    }
                                }
                            }
                            #endregion
                            #region replace the consecutive rests
                            if (restsToReplace.Count > 0)
                            {
                                for (int i = restsToReplace.Count - 1; i >= 0; i--)
                                {
                                    List <int> indToReplace = restsToReplace[i];
                                    int        msDuration   = 0;
                                    int        msPos        = 0;
                                    float      fontSize     = 0F;
                                    for (int j = indToReplace.Count - 1; j >= 0; j--)
                                    {
                                        RestSymbol rest = voice.NoteObjects[indToReplace[j]] as RestSymbol;
                                        Debug.Assert(rest != null);
                                        msDuration += rest.MsDuration;
                                        msPos       = rest.MsPosition;
                                        fontSize    = rest.FontHeight;
                                        voice.NoteObjects.RemoveAt(indToReplace[j]);
                                    }
                                    RestDef    umrd    = new RestDef(msPos, msDuration);
                                    RestSymbol newRest = new RestSymbol(voice, umrd, minimumCrotchetDuration, _pageFormat.MusicFontHeight);
                                    newRest.MsPosition = msPos;
                                    voice.NoteObjects.Insert(indToReplace[0], newRest);
                                }
                            }
                            #endregion
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Returns two bars. The first is the beginning of the argument bar up to absoluteSplitPos,
        /// The second is the end of the argument bar beginning at absoluteSplitPos.
        /// The final UniqueMidiDurationDef in each voice.UniqueMidiDurationDefs list is converted
        /// to a FinalLMDDInVoice object containing an MsDurationToBarline property.
        /// If a chord or rest overlaps a barline, a LocalizedCautionaryChordDef object is created at the
        /// start of the voice.UniqueMidiDurationDefs in the second bar. A LocalizedCautionaryChordDef
        /// object is a kind of chord which is used while justifying systems, but is not displayed and
        /// does not affect performance.
        /// ClefChangeDefs are placed at the end of the first bar, not at the start of the second bar.
        /// </summary>
        protected List <List <VoiceDef> > SplitBar(List <VoiceDef> originalBar, int absoluteSplitPos)
        {
            List <List <VoiceDef> > twoBars   = new List <List <VoiceDef> >();
            List <VoiceDef>         firstBar  = new List <VoiceDef>();
            List <VoiceDef>         secondBar = new List <VoiceDef>();

            twoBars.Add(firstBar);
            twoBars.Add(secondBar);
            int originalBarStartPos = originalBar[0].UniqueDefs[0].MsPosition;
            int originalBarEndPos   =
                originalBar[0].UniqueDefs[originalBar[0].UniqueDefs.Count - 1].MsPosition +
                originalBar[0].UniqueDefs[originalBar[0].UniqueDefs.Count - 1].MsDuration;

            VoiceDef firstBarVoice;
            VoiceDef secondBarVoice;

            foreach (VoiceDef voice in originalBar)
            {
                TrkDef outputVoice = voice as TrkDef;
                if (outputVoice != null)
                {
                    firstBarVoice = new TrkDef(outputVoice.MidiChannel, new List <IUniqueDef>());
                    firstBar.Add(firstBarVoice);
                    secondBarVoice = new TrkDef(outputVoice.MidiChannel, new List <IUniqueDef>());
                    secondBar.Add(secondBarVoice);
                }
                else
                {
                    firstBarVoice = new InputVoiceDef();
                    firstBar.Add(firstBarVoice);
                    secondBarVoice = new InputVoiceDef();
                    secondBar.Add(secondBarVoice);
                }
                foreach (IUniqueDef iUnique in voice.UniqueDefs)
                {
                    int udMsDuration = iUnique.MsDuration;
                    IUniqueSplittableChordDef uniqueChordDef = iUnique as IUniqueSplittableChordDef;
                    if (uniqueChordDef != null)
                    {
                        udMsDuration = (uniqueChordDef.MsDurationToNextBarline == null) ? iUnique.MsDuration : (int)uniqueChordDef.MsDurationToNextBarline;
                    }

                    int udEndPos = iUnique.MsPosition + udMsDuration;

                    if (iUnique.MsPosition >= absoluteSplitPos)
                    {
                        if (iUnique.MsPosition == absoluteSplitPos && iUnique is ClefChangeDef)
                        {
                            firstBarVoice.UniqueDefs.Add(iUnique);
                        }
                        else
                        {
                            Debug.Assert(udEndPos <= originalBarEndPos);
                            secondBarVoice.UniqueDefs.Add(iUnique);
                        }
                    }
                    else if (udEndPos > absoluteSplitPos)
                    {
                        int durationAfterBarline = udEndPos - absoluteSplitPos;
                        if (iUnique is RestDef)
                        {
                            // This is a rest. Split it.
                            RestDef firstRestHalf = new RestDef(iUnique.MsPosition, absoluteSplitPos - iUnique.MsPosition);
                            firstBarVoice.UniqueDefs.Add(firstRestHalf);

                            RestDef secondRestHalf = new RestDef(absoluteSplitPos, durationAfterBarline);
                            secondBarVoice.UniqueDefs.Add(secondRestHalf);
                        }
                        else if (iUnique is CautionaryChordDef)
                        {
                            // This is a cautionary chord. Set the position of the following barline, and
                            // Add an LocalizedCautionaryChordDef at the beginning of the following bar.
                            iUnique.MsDuration = absoluteSplitPos - iUnique.MsPosition;
                            firstBarVoice.UniqueDefs.Add(iUnique);

                            CautionaryChordDef secondLmdd = new CautionaryChordDef((IUniqueChordDef)iUnique, absoluteSplitPos, durationAfterBarline);
                            secondBarVoice.UniqueDefs.Add(secondLmdd);
                        }
                        else
                        {
                            // This is a MidiChordDef or a InputChordDef.
                            // Set the position of the following barline, and add a CautionaryChordDef at the beginning
                            // of the following bar.
                            if (uniqueChordDef != null)
                            {
                                uniqueChordDef.MsDurationToNextBarline = absoluteSplitPos - iUnique.MsPosition;
                            }

                            firstBarVoice.UniqueDefs.Add((IUniqueDef)uniqueChordDef);

                            CautionaryChordDef secondLmdd = new CautionaryChordDef((IUniqueChordDef)uniqueChordDef,
                                                                                   absoluteSplitPos, durationAfterBarline);
                            secondBarVoice.UniqueDefs.Add(secondLmdd);
                        }
                    }
                    else
                    {
                        Debug.Assert(udEndPos <= absoluteSplitPos && iUnique.MsPosition >= originalBarStartPos);
                        firstBarVoice.UniqueDefs.Add(iUnique);
                    }
                }
            }
            return(twoBars);
        }
        /// <summary>
        /// This function creates only one bar, but with VoiceDef objects.
        /// </summary>
        List <VoiceDef> CreateBar2(int bar2StartMsPos)
        {
            List <VoiceDef> bar = new List <VoiceDef>();

            byte          channel = 0;
            List <TrkDef> trkDefs = new List <TrkDef>();

            foreach (Palette palette in _palettes)
            {
                bar.Add(new TrkDef(channel, new List <IUniqueDef>()));
                TrkDef trkDef = palette.NewTrkDef(channel);
                trkDef.SetMsDuration(6000);
                trkDefs.Add(trkDef);
                ++channel;
            }

            int msPosition        = bar2StartMsPos;
            int maxBarMsPos       = 0;
            int startMsDifference = 1500;

            for (int i = 0; i < trkDefs.Count; ++i)
            {
                int maxMsPos = WriteVoiceMidiDurationDefsInBar2(bar[i], trkDefs[i], msPosition, bar2StartMsPos);
                maxBarMsPos = maxBarMsPos > maxMsPos ? maxBarMsPos : maxMsPos;
                msPosition += startMsDifference;
            }

            // now add the final rest in the bar
            for (int i = 0; i < trkDefs.Count; ++i)
            {
                int mdsdEndPos = trkDefs[i].EndMsPosition;
                if (maxBarMsPos > mdsdEndPos)
                {
                    RestDef rest2Def = new RestDef(mdsdEndPos, maxBarMsPos - mdsdEndPos);
                    bar[i].UniqueDefs.Add(rest2Def);
                }
            }

            InputVoiceDef inputVoiceDef = new InputVoiceDef(maxBarMsPos - bar2StartMsPos);

            inputVoiceDef.StartMsPosition = bar2StartMsPos;
            int msPos = bar2StartMsPos;

            for (int i = 0; i < bar.Count; ++i)
            {
                TrkOn        trkRef  = new TrkOn((byte)i, msPos, 12, null);
                List <TrkOn> trkRefs = new List <TrkOn>()
                {
                    trkRef
                };
                TrkOns seqDef = new TrkOns(trkRefs, null);

                InputNoteDef inputNoteDef = new InputNoteDef(64, seqDef, null, null);

                List <InputNoteDef> inputNoteDefs = new List <InputNoteDef>()
                {
                    inputNoteDef
                };
                InputChordDef inputChordDef = new InputChordDef(msPos, startMsDifference, inputNoteDefs);
                inputVoiceDef.InsertInRest(inputChordDef);
                msPos += startMsDifference;
            }

            bar.Add(inputVoiceDef);
            return(bar);
        }
        List <VoiceDef> CreateBar1()
        {
            List <VoiceDef> bar = new List <VoiceDef>();

            byte channel = 0;

            foreach (Palette palette in _palettes)
            {
                TrkDef trkDef = new TrkDef(channel, new List <IUniqueDef>());
                bar.Add(trkDef);
                WriteVoiceMidiDurationDefs1(trkDef, palette);
                ++channel;
            }

            InputVoiceDef inputVoiceDef     = new InputVoiceDef();
            VoiceDef      bottomOutputVoice = bar[0];

            foreach (IUniqueDef iud in bottomOutputVoice.UniqueDefs)
            {
                MidiChordDef mcd = iud as MidiChordDef;
                RestDef      rd  = iud as RestDef;
                if (mcd != null)
                {
                    List <IUniqueDef> iuds = new List <IUniqueDef>()
                    {
                        (IUniqueDef)mcd
                    };

                    // Note that the msPosition of the trkDef is trkDef.StartMsPosition (= iuds[0].msPosition),
                    // which may be greater than the InputChordDef's msPosition
                    TrkDef trkDef = new TrkDef(bottomOutputVoice.MidiChannel, iuds);

                    // If non-null, arg2 overrides the inputControls attached to the InputNote or InputChord.
                    TrkOn        trkRef  = new TrkOn(trkDef, null);
                    List <TrkOn> trkRefs = new List <TrkOn>()
                    {
                        trkRef
                    };
                    TrkOns trkOns = new TrkOns(trkRefs, null);

                    byte      displayPitch = (byte)(mcd.NotatedMidiPitches[0] + 36);
                    Pressure  pressure     = new Pressure(0, null);
                    Pressures pressures    = new Pressures(new List <Pressure>()
                    {
                        pressure
                    }, null);
                    TrkOff        trkOff         = new TrkOff(trkRef.TrkMidiChannel, mcd.MsPosition, null);
                    List <TrkOff> noteOffTrkOffs = new List <TrkOff>()
                    {
                        trkOff
                    };
                    TrkOffs trkOffs = new TrkOffs(noteOffTrkOffs, null);

                    InputNoteDef inputNoteDef = new InputNoteDef(displayPitch,
                                                                 trkOns, null,
                                                                 pressures,
                                                                 null, trkOffs,
                                                                 null);

                    List <InputNoteDef> inputNoteDefs = new List <InputNoteDef>()
                    {
                        inputNoteDef
                    };

                    // The InputChordDef's msPosition must be <= the msPosition of any of the contained trkRefs
                    InputChordDef icd = new InputChordDef(mcd.MsPosition, mcd.MsDuration, inputNoteDefs);

                    inputVoiceDef.UniqueDefs.Add(icd);
                }
                else if (rd != null)
                {
                    RestDef newRest = new RestDef(rd.MsPosition, rd.MsDuration);
                    inputVoiceDef.UniqueDefs.Add(newRest);
                }
            }

            #region set cascading inputControls on the first InputChordDef  (for testing)
            InputChordDef inputChordDef1 = inputVoiceDef.UniqueDefs[0] as InputChordDef;             // no need to check for null here.

            InputControls chordInputControls = new InputControls();

            chordInputControls.VelocityOption  = VelocityOption.overridden;
            chordInputControls.MinimumVelocity = 19;
            inputChordDef1.InputControls       = chordInputControls;

            InputControls noteInputControls = new InputControls();
            noteInputControls.VelocityOption              = VelocityOption.scaled;
            noteInputControls.MinimumVelocity             = 20;
            inputChordDef1.InputNoteDefs[0].InputControls = noteInputControls;

            #endregion

            bar.Add(inputVoiceDef);

            return(bar);
        }
Beispiel #10
0
        /// <summary>
        /// Returns either a new RestDef or a new MidiChordDef
        /// In both cases, MsPosition is set to zero, Lyric is set to null.
        /// </summary>
        private DurationDef GetDurationDef(int index)
        {
            DurationDef            rval = null;
            BasicChordMidiSettings bcms = _basicChordMidiSettings;

            if (bcms.MidiPitches[index].Count == 0)
            {
                /// RestDefs are immutable, and have no MsPosition property.
                /// UniqueRestDefs are mutable RestDefs with both MsPositon and MsDuration properties.
                int restMsDuration = bcms.Durations[index];
                rval = new RestDef(0, restMsDuration);
            }
            else
            {
                /// Create a new MidiChordDef (with msPosition=0, lyric=null)
                bool        hasChordOff        = BoolOrDefaultValue(bcms.ChordOffs, index, M.DefaultHasChordOff); // true
                int         duration           = bcms.Durations[index];
                List <byte> rootMidiPitches    = bcms.MidiPitches[index];
                List <byte> rootMidiVelocities = bcms.Velocities[index];

                byte?       bankIndex               = ByteOrNull(_bankIndices, index);
                byte?       patchIndex              = ByteOrNull(_patchIndices, index);
                byte        pitchwheelDeviation     = ByteOrDefaultValue(_pitchwheelDeviations, index, M.DefaultPitchWheelDeviation); // 2
                List <byte> pitchwheelEnvelope      = ListByte(_pitchwheelEnvelopes, index);
                List <byte> panEnvelope             = ListByte(_panEnvelopes, index);
                List <byte> modulationWheelEnvelope = ListByte(_modulationWheelEnvelopes, index);
                List <byte> expressionEnvelope      = ListByte(_expressionEnvelopes, index);

                MidiChordSliderDefs midiChordSliderDefs =
                    new MidiChordSliderDefs(pitchwheelEnvelope,
                                            panEnvelope,
                                            modulationWheelEnvelope,
                                            expressionEnvelope);

                OrnamentSettings         os = _ornamentSettings;
                List <BasicMidiChordDef> basicMidiChordDefs = new List <BasicMidiChordDef>();
                int ornamentNumber;
                if (os == null || _ornamentNumbers[index] == 0)
                {
                    ornamentNumber = 0;
                    BasicMidiChordDef bmcd = new BasicMidiChordDef(duration, bankIndex, patchIndex, hasChordOff, rootMidiPitches, rootMidiVelocities);
                    basicMidiChordDefs.Add(bmcd);
                }
                else
                {
                    ornamentNumber = _ornamentNumbers[index];
                    int ornamentMinMsDuration = IntOrDefaultValue(_ornamentMinMsDurations, index, M.DefaultOrnamentMinimumDuration); // 1

                    List <int> ornamentValues = os.OrnamentValues[_ornamentNumbers[index] - 1];

                    for (int i = 0; i < ornamentValues.Count; ++i)
                    {
                        int         oIndex       = ornamentValues[i] - 1;
                        bool        oHasChordOff = BoolOrDefaultValue(os.BasicChordMidiSettings.ChordOffs, oIndex, M.DefaultHasChordOff);
                        int         oDuration    = os.BasicChordMidiSettings.Durations[oIndex];
                        List <byte> oMidiPitches = os.BasicChordMidiSettings.MidiPitches[oIndex];
                        List <byte> oVelocities  = os.BasicChordMidiSettings.Velocities[oIndex];
                        byte?       oBank        = ByteOrNull(os.BankIndices, oIndex);
                        byte?       oPatch       = ByteOrNull(os.PatchIndices, oIndex);

                        BasicMidiChordDef bmcd = new BasicMidiChordDef(oDuration, oBank, oPatch, oHasChordOff, oMidiPitches, oVelocities);
                        basicMidiChordDefs.Add(bmcd);
                    }

                    // The basicMidiChordDefs currently contain the values from the ornaments form.
                    // All oBank and oPatch values will be null if the corresponding field in the ornament form was empty.
                    // The durations, pitches and velocities are relative to the main palette's values.

                    RemoveDuplicateBankAndPatchValues(basicMidiChordDefs);

                    if (basicMidiChordDefs[0].BankIndex == null)
                    {
                        basicMidiChordDefs[0].BankIndex = bankIndex; // can be null
                    }
                    if (basicMidiChordDefs[0].PatchIndex == null)
                    {
                        basicMidiChordDefs[0].PatchIndex = patchIndex;
                    }

                    Debug.Assert(basicMidiChordDefs[0].PatchIndex != null);

                    basicMidiChordDefs = Moritz.Spec.MidiChordDef.FitToDuration(basicMidiChordDefs, duration, ornamentMinMsDuration);

                    foreach (BasicMidiChordDef b in basicMidiChordDefs)
                    {
                        List <byte> combinedPitches = new List <byte>();
                        foreach (byte pitch in b.Pitches)
                        {
                            foreach (byte rootMidiPitch in rootMidiPitches)
                            {
                                combinedPitches.Add(M.MidiValue(rootMidiPitch + pitch));
                            }
                        }
                        b.Pitches = combinedPitches;

                        List <byte> combinedVelocities = new List <byte>();
                        foreach (byte velocity in b.Velocities)
                        {
                            foreach (byte rootMidiVelocity in rootMidiVelocities)
                            {
                                combinedVelocities.Add(M.MidiValue(rootMidiVelocity + velocity));
                            }
                        }
                        b.Velocities = combinedVelocities;
                    }
                }

                rval = new MidiChordDef(
                    duration,
                    pitchwheelDeviation,
                    hasChordOff,
                    rootMidiPitches,
                    ornamentNumber,
                    midiChordSliderDefs,
                    basicMidiChordDefs);
            }
            return(rval);
        }