/// <summary>
        /// 音符に付随するピッチベンドの情報を、PIT・PBS カーブに反映する
        /// </summary>
        /// <param name="item">音符</param>
        /// <param name="pitchBend">PIT カーブ</param>
        /// <param name="pitchBendSensitivity">PBS カーブ</param>
        /// <param name="tempoTable">テンポ情報</param>
        protected void reflectNoteEventPitch( VsqEvent item, VsqBPList pitchBend, VsqBPList pitchBendSensitivity, TempoVector tempoTable )
        {
            if ( item.ID.type != VsqIDType.Anote ) return;
            
            // AquesTone2 では、note on と同 clock にピッチベンドイベントを送らないと音程が反映されないので、必ずピッチイベントが送られるようにする
            pitchBend.add( item.Clock, pitchBend.getValue( item.Clock ) );

            if ( item.ID.VibratoHandle == null ) {
                return;
            }

            int startClock = item.Clock + item.ID.VibratoDelay;
            int vibratoLength = item.ID.Length - item.ID.VibratoDelay;

            var iterator = new VibratoPointIteratorByClock( tempoTable,
                                                            item.ID.VibratoHandle.RateBP, item.ID.VibratoHandle.StartRate,
                                                            item.ID.VibratoHandle.DepthBP, item.ID.VibratoHandle.StartDepth,
                                                            startClock, vibratoLength );
            var pitContext = new ByRef<int>( 0 );
            var pbsContext = new ByRef<int>( 0 );

            int pitAtEnd = pitchBend.getValue( startClock + vibratoLength );
            int pbsAtEnd = pitchBendSensitivity.getValue( startClock + vibratoLength );
            var pitBackup = (VsqBPList)pitchBend.Clone();
            var pbsBackup = (VsqBPList)pitchBendSensitivity.Clone();

            bool resetPBS = false;
            double maxNetPitchBendInCent = 0.0;
            for ( int clock = startClock; clock < startClock + vibratoLength && iterator.hasNext(); ++clock ) {
                double vibratoPitchBendInCent = iterator.next() * 100.0;
                int pit = pitchBend.getValue( clock, pitContext );
                int pbs = pitchBendSensitivity.getValue( clock, pbsContext );
                const double pow2_13 = 8192;
                double netPitchBendInCent = (pbs * pit / pow2_13) * 100.0 + vibratoPitchBendInCent;
                maxNetPitchBendInCent = Math.Max( maxNetPitchBendInCent, Math.Abs( netPitchBendInCent ) );
                int draftPitchBend = (int)Math.Round( (netPitchBendInCent / 100.0) * pow2_13 / pbs );

                if ( draftPitchBend < pitchBend.Minimum || pitchBend.Maximum < draftPitchBend ) {
                    // pbs を変更せずにビブラートによるピッチベンドを反映しようとすると、
                    // pit が範囲を超えてしまう。
                    resetPBS = true;
                } else {
                    if ( draftPitchBend != pit ) {
                        pitchBend.add( clock, draftPitchBend );
                    }
                }
            }

            if ( !resetPBS ) {
                return;
            }

            pitchBend.Data = pitBackup.Data;

            // ピッチベンドの最大値を実現するのに必要なPBS
            int requiredPitchbendSensitivity = (int)Math.Ceiling( maxNetPitchBendInCent / 100.0 );
            int pseudoMaxPitchbendSensitivity = 12; // AquesTone2 は最大 12 半音までベンドできる。
            if ( requiredPitchbendSensitivity < pitchBendSensitivity.Minimum ) requiredPitchbendSensitivity = pitchBendSensitivity.Minimum;
            if ( pseudoMaxPitchbendSensitivity < requiredPitchbendSensitivity ) requiredPitchbendSensitivity = pseudoMaxPitchbendSensitivity;

            {
                int i = 0;
                while ( i < pitchBend.size() ) {
                    var clock = pitchBend.getKeyClock( i );
                    if ( startClock <= clock && clock < startClock + vibratoLength ) {
                        pitchBend.removeElementAt( i );
                    } else {
                        ++i;
                    }
                }
            }
            {
                int i = 0;
                while ( i < pitchBendSensitivity.size() ) {
                    var clock = pitchBendSensitivity.getKeyClock( i );
                    if ( startClock <= clock && clock < startClock + vibratoLength ) {
                        pitchBendSensitivity.removeElementAt( i );
                    } else {
                        ++i;
                    }
                }
            }
            if ( pitchBendSensitivity.getValue( startClock ) != requiredPitchbendSensitivity ) {
                pitchBendSensitivity.add( startClock, requiredPitchbendSensitivity );
            }
            pitchBend.add( startClock + vibratoLength, pitAtEnd );
            pitchBendSensitivity.add( startClock + vibratoLength, pbsAtEnd );

            iterator.rewind();
            pitContext.value = 0;
            pbsContext.value = 0;
            int lastPitchBend = pitchBend.getValue( startClock );
            for ( int clock = startClock; clock < startClock + vibratoLength && iterator.hasNext(); ++clock ) {
                double vibratoPitchBendInCent = iterator.next() * 100.0;
                int pit = pitBackup.getValue( clock, pitContext );
                int pbs = pbsBackup.getValue( clock, pbsContext );

                const double pow2_13 = 8192;
                double netPitchBendInCent = (pbs * pit / pow2_13) * 100.0 + vibratoPitchBendInCent;
                maxNetPitchBendInCent = Math.Max( maxNetPitchBendInCent, Math.Abs( netPitchBendInCent ) );
                int draftPitchBend = (int)Math.Round((netPitchBendInCent / 100.0) * pow2_13 / requiredPitchbendSensitivity);
                if ( draftPitchBend < pitchBend.Minimum ) draftPitchBend = pitchBend.Minimum;
                if ( pitchBend.Maximum < draftPitchBend ) draftPitchBend = pitchBend.Maximum;
                if ( draftPitchBend != lastPitchBend ) {
                    pitchBend.add( clock, draftPitchBend );
                    lastPitchBend = draftPitchBend;
                }
            }
        }
        /// <summary>
        /// 音符に付随するピッチベンドの情報を、PIT・PBS カーブに反映する
        /// </summary>
        /// <param name="item">音符</param>
        /// <param name="pitchBend">PIT カーブ</param>
        /// <param name="pitchBendSensitivity">PBS カーブ</param>
        /// <param name="tempoTable">テンポ情報</param>
        protected void reflectNoteEventPitch(VsqEvent item, VsqBPList pitchBend, VsqBPList pitchBendSensitivity, TempoVector tempoTable)
        {
            if (item.ID.type != VsqIDType.Anote)
            {
                return;
            }

            // AquesTone2 では、note on と同 clock にピッチベンドイベントを送らないと音程が反映されないので、必ずピッチイベントが送られるようにする
            pitchBend.add(item.Clock, pitchBend.getValue(item.Clock));

            if (item.ID.VibratoHandle == null)
            {
                return;
            }

            int startClock    = item.Clock + item.ID.VibratoDelay;
            int vibratoLength = item.ID.Length - item.ID.VibratoDelay;

            var iterator = new VibratoPointIteratorByClock(tempoTable,
                                                           item.ID.VibratoHandle.RateBP, item.ID.VibratoHandle.StartRate,
                                                           item.ID.VibratoHandle.DepthBP, item.ID.VibratoHandle.StartDepth,
                                                           startClock, vibratoLength);
            var pitContext = new ByRef <int>(0);
            var pbsContext = new ByRef <int>(0);

            int pitAtEnd  = pitchBend.getValue(startClock + vibratoLength);
            int pbsAtEnd  = pitchBendSensitivity.getValue(startClock + vibratoLength);
            var pitBackup = (VsqBPList)pitchBend.Clone();
            var pbsBackup = (VsqBPList)pitchBendSensitivity.Clone();

            bool   resetPBS = false;
            double maxNetPitchBendInCent = 0.0;

            for (int clock = startClock; clock < startClock + vibratoLength && iterator.hasNext(); ++clock)
            {
                double       vibratoPitchBendInCent = iterator.next() * 100.0;
                int          pit                = pitchBend.getValue(clock, pitContext);
                int          pbs                = pitchBendSensitivity.getValue(clock, pbsContext);
                const double pow2_13            = 8192;
                double       netPitchBendInCent = (pbs * pit / pow2_13) * 100.0 + vibratoPitchBendInCent;
                maxNetPitchBendInCent = Math.Max(maxNetPitchBendInCent, Math.Abs(netPitchBendInCent));
                int draftPitchBend = (int)Math.Round((netPitchBendInCent / 100.0) * pow2_13 / pbs);

                if (draftPitchBend < pitchBend.Minimum || pitchBend.Maximum < draftPitchBend)
                {
                    // pbs を変更せずにビブラートによるピッチベンドを反映しようとすると、
                    // pit が範囲を超えてしまう。
                    resetPBS = true;
                }
                else
                {
                    if (draftPitchBend != pit)
                    {
                        pitchBend.add(clock, draftPitchBend);
                    }
                }
            }

            if (!resetPBS)
            {
                return;
            }

            pitchBend.Data = pitBackup.Data;

            // ピッチベンドの最大値を実現するのに必要なPBS
            int requiredPitchbendSensitivity  = (int)Math.Ceiling(maxNetPitchBendInCent / 100.0);
            int pseudoMaxPitchbendSensitivity = 12; // AquesTone2 は最大 12 半音までベンドできる。

            if (requiredPitchbendSensitivity < pitchBendSensitivity.Minimum)
            {
                requiredPitchbendSensitivity = pitchBendSensitivity.Minimum;
            }
            if (pseudoMaxPitchbendSensitivity < requiredPitchbendSensitivity)
            {
                requiredPitchbendSensitivity = pseudoMaxPitchbendSensitivity;
            }

            {
                int i = 0;
                while (i < pitchBend.size())
                {
                    var clock = pitchBend.getKeyClock(i);
                    if (startClock <= clock && clock < startClock + vibratoLength)
                    {
                        pitchBend.removeElementAt(i);
                    }
                    else
                    {
                        ++i;
                    }
                }
            }
            {
                int i = 0;
                while (i < pitchBendSensitivity.size())
                {
                    var clock = pitchBendSensitivity.getKeyClock(i);
                    if (startClock <= clock && clock < startClock + vibratoLength)
                    {
                        pitchBendSensitivity.removeElementAt(i);
                    }
                    else
                    {
                        ++i;
                    }
                }
            }
            if (pitchBendSensitivity.getValue(startClock) != requiredPitchbendSensitivity)
            {
                pitchBendSensitivity.add(startClock, requiredPitchbendSensitivity);
            }
            pitchBend.add(startClock + vibratoLength, pitAtEnd);
            pitchBendSensitivity.add(startClock + vibratoLength, pbsAtEnd);

            iterator.rewind();
            pitContext.value = 0;
            pbsContext.value = 0;
            int lastPitchBend = pitchBend.getValue(startClock);

            for (int clock = startClock; clock < startClock + vibratoLength && iterator.hasNext(); ++clock)
            {
                double vibratoPitchBendInCent = iterator.next() * 100.0;
                int    pit = pitBackup.getValue(clock, pitContext);
                int    pbs = pbsBackup.getValue(clock, pbsContext);

                const double pow2_13            = 8192;
                double       netPitchBendInCent = (pbs * pit / pow2_13) * 100.0 + vibratoPitchBendInCent;
                maxNetPitchBendInCent = Math.Max(maxNetPitchBendInCent, Math.Abs(netPitchBendInCent));
                int draftPitchBend = (int)Math.Round((netPitchBendInCent / 100.0) * pow2_13 / requiredPitchbendSensitivity);
                if (draftPitchBend < pitchBend.Minimum)
                {
                    draftPitchBend = pitchBend.Minimum;
                }
                if (pitchBend.Maximum < draftPitchBend)
                {
                    draftPitchBend = pitchBend.Maximum;
                }
                if (draftPitchBend != lastPitchBend)
                {
                    pitchBend.add(clock, draftPitchBend);
                    lastPitchBend = draftPitchBend;
                }
            }
        }