Esempio n. 1
0
 public PointD next()
 {
     if (first)
     {
         i     = 0;
         first = false;
         return(new PointD(sec0, 0));
     }
     else
     {
         i++;
         if (i < count)
         {
             double t_sec = sec0 + sec_resolution * i;
             double clock = vsq.getClockFromSec(t_sec);
             if (sec0 <= t_sec && t_sec <= sec0 + fadewidth)
             {
                 amplitude *= (float)(t_sec - sec0) / fadewidth;
             }
             if (sec1 - fadewidth <= t_sec && t_sec <= sec1)
             {
                 amplitude *= (float)(sec1 - t_sec) / fadewidth;
             }
             phase += omega * (t_sec - sec);
             PointD ret = new PointD(t_sec, amplitude * Math.Sin(phase));
             float  v   = (float)(clock - clock_start) / (float)clock_width;
             int    r   = rate.getValue(v, start_rate);
             int    d   = depth.getValue(v, start_depth);
             amplitude = d * 2.5f / 127.0f / 2.0f;
             period    = getPeriodFromRate(r);
             omega     = (float)(2.0 * Math.PI / period);
             sec       = t_sec;
             return(ret);
         }
         else
         {
             return(new PointD());
         }
     }
 }
Esempio n. 2
0
        public static void RestartMetronome()
        {
            m_stop_metronome_required = false;
            if (m_vsq != null)
            {
                double now     = PortUtil.getCurrentTime();
                double elapsed = ((now - m_started) + 0.25) * m_speed;
                int    clock   = (int)m_vsq.getClockFromSec(m_started_sec + elapsed);

                ByRef <Integer> bar             = new ByRef <Integer>();
                Timesig         timesig         = m_vsq.getTimesigAt(clock, bar);
                int             clock_at_bartop = m_vsq.getClockFromBarCount(bar.value);
                int             clock_step      = 480 * 4 / timesig.denominator;
                int             next_clock      = clock_at_bartop + ((clock - clock_at_bartop) / clock_step + 1) * clock_step;

                MidiQueue mq = new MidiQueue();
                mq.Track    = 0;
                mq.Clock    = next_clock;
                mq.Channel  = 14;
                mq.Program  = ProgramNormal;
                mq.Note     = NoteNormal;
                mq.Velocity = 0x40;
                mq.Done    += new MidiQueueDoneEventHandler(ReGenerateMidiQueue);
                s_queue.add(mq);

                if ((next_clock - clock_at_bartop) % (timesig.numerator * clock_step) == 0)
                {
                    MidiQueue mq_bell = new MidiQueue();
                    mq_bell.Track    = 0;
                    mq_bell.Clock    = next_clock;
                    mq_bell.Channel  = 15;
                    mq_bell.Program  = ProgramBell;
                    mq_bell.Note     = NoteBell;
                    mq_bell.Velocity = 0x40;
                    s_queue.add(mq_bell);
                }
                Collections.sort(s_queue);
            }
        }
        /*private int round5(float X)
         * {
         *  return (int)(Math.Round(X / 5, 0) * 5);
         * }*/
        public void SplitIt()
        {
            dstVibstrBrustEvents.Clear();
            dstPitchBrust.Clear();
            dstParentTable.Clear();
            string PRO = oriEvent.ID.LyricHandle.L0.getPhoneticSymbol();

            if (PRO.IndexOf(',') > 0)
            {
                if (oriEvent.UstEvent.SplitLength > 0)
                {
                    int Len1      = 0;
                    int Len2      = 0;
                    int SplitTime = 0;
                    Len2 = (int)oriEvent.UstEvent.SplitLength;
                    Len1 = oriEvent.ID.getLength() - Len2;

                    /*if (oriEvent.UstEvent.SplitisPercent)
                     * {
                     *  Len2 = (int)(oriEvent.ID.getLength() * (oriEvent.UstEvent.SplitLength / 100.0));
                     *  Len1 = oriEvent.ID.getLength() - Len2;
                     * }
                     * else
                     * {
                     *  Len2 = (int)oriEvent.UstEvent.SplitLength;
                     *  Len1 = oriEvent.ID.getLength() - Len2;
                     * }
                     * if (Len1 <= 0)
                     * {
                     *  Len1 = oriEvent.ID.getLength() / 2;
                     *  Len2 = oriEvent.ID.getLength() - Len1;
                     * }*/

                    /*int PitchCountStartPoint=(int)Math.Round(oriEvent.Clock-oriEvent.UstEvent.getPreUtterance(),0);
                     * Len1 = Cell5(PitchCountStartPoint + Len1) - PitchCountStartPoint;
                     * Len2 = oriEvent.ID.getLength() - Len1;
                     * SplitTime=(Len1 + oriEvent.Clock);
                     */

                    OtoArgs oa = new OtoArgs();
                    if (vdb != null)
                    {
                        int CheckNote = oriEvent.ID.Note;
                        if (oriEvent.UstEvent != null)
                        {
                            CheckNote = oriEvent.UstEvent.ReplaceNoteID > 0 ? oriEvent.UstEvent.ReplaceNoteID : oriEvent.ID.Note;
                        }
                        oa = vdb.attachFileNameFromLyric(PRO.Split(',')[1], CheckNote);
                    }
                    if (oa.fileName == null ||
                        (oa.fileName != null && oa.fileName == ""))
                    {
                        oriEvent.ID.LyricHandle.L0.setPhoneticSymbol(PRO.Split(',')[0]);
                        //oriEvent.UstEvent.setVoiceOverlap(oriEvent.UstEvent.getVoiceOverlap() + preover);
                        dstVibstrBrustEvents.Add(oriEvent, oriVibstrBrustEvents);
                        dstPitchBrust.Add(oriEvent, oriPitchBrust);
                        dstParentTable.Add(oriEvent, oriEvent);
                        return;
                    }
                    int SplitLen = (int)oriEvent.UstEvent.SplitLength;
                    if (oriEvent.UstEvent.SplitisPercent)
                    {
                        SplitLen = (int)(oriEvent.ID.getLength() * SplitLen / 100.0);
                    }

                    float V2PreUttr   = oa.msPreUtterance + oriEvent.UstEvent.SplitSTP;
                    float V1PreUttr   = oriEvent.UstEvent.getPreUtterance() + oriEvent.UstEvent.getStartPoint();
                    int   RealV1Start = (int)mVsq.getClockFromSec(mVsq.getSecFromClock(oriEvent.Clock) - V1PreUttr / 1000.0);
                    int   RealV2Start = (int)mVsq.getClockFromSec(mVsq.getSecFromClock(oriEvent.Clock + Len1) - V2PreUttr / 1000.0);
                    int   R           = Cell5(RealV2Start - RealV1Start);
                    int   Dert        = (RealV2Start - RealV1Start) - R;
                    if (Dert > 3)
                    {
                        Len1 = Len1 + ((5 - Dert) > 0 ? (5 - Dert) : 0);
                    }
                    else
                    {
                        Len1 = Len1 - Dert;
                    }
                    Len2      = oriEvent.ID.getLength() - Len1;
                    SplitTime = (Len1 + oriEvent.Clock);
                    int CrossLen = (int)((oa.msOverlap) + oriEvent.UstEvent.SplitVoiceOverlap);


                    VsqEvent V1 = (VsqEvent)oriEvent.clone();
                    V1.ID.LyricHandle.L0.setPhoneticSymbol(PRO.Split(',')[0]);
                    V1.Clock = oriEvent.Clock;
                    V1.ID.setLength(Len1);
                    V1.UstEvent.setVoiceOverlap(V1.UstEvent.getVoiceOverlap() + V1.UstEvent.NotePreOverlap);
                    UstEnvelope env = oriEvent.UstEvent.getEnvelope();
                    if (env == null)
                    {
                        env = new UstEnvelope();
                    }
                    env.p3 = CrossLen;
                    env.p4 = 0;
                    env.v4 = 0;
                    V1.UstEvent.setEnvelope(env);

                    VsqEvent V2 = (VsqEvent)oriEvent.clone();
                    V2.ID.LyricHandle.L0.setPhoneticSymbol(PRO.Split(',')[1]);
                    V2.Clock = SplitTime;
                    V2.ID.setLength(Len2);
                    V2.UstEvent.setVoiceOverlap(CrossLen);
                    V2.UstEvent.setPreUtterance(oa.msPreUtterance);
                    V2.UstEvent.setStartPoint(V2.UstEvent.SplitSTP);
                    V2.UstEvent.LeftLimit = 0;
                    env = oriEvent.UstEvent.getEnvelope();
                    if (env == null)
                    {
                        env = new UstEnvelope();
                    }
                    env.p2 = CrossLen;
                    env.v2 = env.v2 - V1.UstEvent.MoreOver;
                    if (env.v2 < 0)
                    {
                        env.v2 = 0;
                    }
                    env.p1 = 0;
                    env.v1 = 0;
                    if (env.p5 > 0)
                    {
                        env.p5 = env.p5 - Len1;
                    }
                    V2.UstEvent.setEnvelope(env);


                    dstVibstrBrustEvents.Add(V1, oriVibstrBrustEvents);
                    dstPitchBrust.Add(V1, oriPitchBrust);
                    dstParentTable.Add(V1, oriEvent);
                    dstVibstrBrustEvents.Add(V2, oriVibstrBrustEvents);
                    dstPitchBrust.Add(V2, oriPitchBrust);
                    dstParentTable.Add(V2, oriEvent);
                }
                else
                {
                    if (oriEvent.ID.LyricHandle.L0.getPhoneticSymbol().IndexOf(",") > 0)
                    {
                        oriEvent.ID.LyricHandle.L0.setPhoneticSymbol(PRO.Split(',')[0]);
                    }
                    dstVibstrBrustEvents.Add(oriEvent, oriVibstrBrustEvents);
                    oriEvent.UstEvent.setVoiceOverlap(oriEvent.UstEvent.getVoiceOverlap() + oriEvent.UstEvent.NotePreOverlap);
                    dstPitchBrust.Add(oriEvent, oriPitchBrust);
                    dstParentTable.Add(oriEvent, oriEvent);
                }
            }
            else
            {
                dstVibstrBrustEvents.Add(oriEvent, oriVibstrBrustEvents);
                oriEvent.UstEvent.setVoiceOverlap(oriEvent.UstEvent.getVoiceOverlap() + oriEvent.UstEvent.NotePreOverlap);
                dstPitchBrust.Add(oriEvent, oriPitchBrust);
                dstParentTable.Add(oriEvent, oriEvent);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="vsq"></param>
        /// <param name="track"></param>
        /// <param name="clock_start"></param>
        /// <param name="clock_end"></param>
        /// <returns></returns>
        private TreeMap<Integer, MidiEventQueue> generateMidiEvent( VsqFileEx vsq, int track, int clock_start, int clock_end )
        {
            TreeMap<Integer, MidiEventQueue> list = new TreeMap<Integer, MidiEventQueue>();
            VsqTrack t = vsq.Track.get( track );

            // 歌手変更
            for ( Iterator<VsqEvent> itr = t.getSingerEventIterator(); itr.hasNext(); ) {
                VsqEvent item = itr.next();
                if ( clock_start <= item.Clock && item.Clock <= clock_end ) {
                    if ( item.ID.IconHandle == null ) {
                        continue;
                    }
                    int program = item.ID.IconHandle.Program;
                    if ( 0 > program || program >= AquesToneDriver.SINGERS.Length ) {
                        program = 0;
                    }
                    ParameterEvent singer = new ParameterEvent();
                    singer.index = mDriver.phontParameterIndex;
                    singer.value = program + 0.01f;
                    if ( !list.containsKey( item.Clock ) ) {
                        list.put( item.Clock, new MidiEventQueue() );
                    }
                    MidiEventQueue queue = list.get( item.Clock );
                    if ( queue.param == null ) {
                        queue.param = new Vector<ParameterEvent>();
                    }
                    queue.param.add( singer );
                } else if ( clock_end < item.Clock ) {
                    break;
                }
            }

            // ノートon, off
            Vector<Point> pit_send = new Vector<Point>(); // PITが追加されたゲートタイム。音符先頭の分を重複して送信するのを回避するために必要。
            VsqBPList pit = t.getCurve( "pit" );
            VsqBPList pbs = t.getCurve( "pbs" );
            VsqBPList dyn = t.getCurve( "dyn" );
            VsqBPList bre = t.getCurve( "bre" );
            VsqBPList cle = t.getCurve( "cle" );
            VsqBPList por = t.getCurve( "por" );
            for ( Iterator<VsqEvent> itr = t.getNoteEventIterator(); itr.hasNext(); ) {
                VsqEvent item = itr.next();
                int endclock = item.Clock + item.ID.getLength();
                boolean contains_start = clock_start <= item.Clock && item.Clock <= clock_end;
                boolean contains_end = clock_start <= endclock && endclock <= clock_end;
                if ( contains_start || contains_end ) {
                    if ( contains_start ) {
                        #region contains_start
                        // noteonのゲートタイムが,範囲に入っている
                        // noteon MIDIイベントを作成
                        String lyric = item.ID.LyricHandle.L0.Phrase;
                        String katakana = KanaDeRomanization.hiragana2katakana( KanaDeRomanization.Attach( lyric ) );
                        int index = -1;
                        for ( int i = 0; i < AquesToneDriver.PHONES.Length; i++ ) {
                            if ( katakana.Equals( AquesToneDriver.PHONES[i] ) ) {
                                index = i;
                                break;
                            }
                        }
                        if ( index >= 0 ) {
                            if ( !list.containsKey( item.Clock ) ) {
                                list.put( item.Clock, new MidiEventQueue() );
                            }
                            MidiEventQueue queue = list.get( item.Clock );
                            if ( queue.noteon == null ) {
                                queue.noteon = new Vector<MidiEvent>();
                            }

                            // index行目に移動するコマンドを贈る
                            MidiEvent moveline = new MidiEvent();
                            moveline.firstByte = 0xb0;
                            moveline.data = new[] { 0x0a, index };
                            MidiEvent noteon = new MidiEvent();
                            noteon.firstByte = 0x90;
                            noteon.data = new int[] { item.ID.Note, item.ID.Dynamics };
                            Vector<MidiEvent> add = Arrays.asList( new MidiEvent[] { moveline, noteon } );
                            queue.noteon.addAll( add );
                            pit_send.add( new Point( item.Clock, item.Clock ) );
                        }

                        /* 音符頭で設定するパラメータ */
                        // Release
                        MidiEventQueue q = null;
                        if ( !list.containsKey( item.Clock ) ) {
                            q = new MidiEventQueue();
                        } else {
                            q = list.get( item.Clock );
                        }
                        if ( q.param == null ) {
                            q.param = new Vector<ParameterEvent>();
                        }

                        String strRelease = VsqFileEx.getEventTag( item, VsqFileEx.TAG_VSQEVENT_AQUESTONE_RELEASE );
                        int release = 64;
                        try {
                            release = str.toi( strRelease );
                        } catch ( Exception ex ) {
                            Logger.write( typeof( AquesToneWaveGenerator ) + ".generateMidiEvent; ex=" + ex + "\n" );
                            release = 64;
                        }
                        ParameterEvent pe = new ParameterEvent();
                        pe.index = mDriver.releaseParameterIndex;
                        pe.value = release / 127.0f;
                        q.param.add( pe );

                        // dyn
                        int dynAtStart = dyn.getValue( item.Clock );
                        ParameterEvent peDyn = new ParameterEvent();
                        peDyn.index = mDriver.volumeParameterIndex;
                        peDyn.value = (float)(dynAtStart - dyn.getMinimum()) / (float)(dyn.getMaximum() - dyn.getMinimum());
                        q.param.add( peDyn );

                        // bre
                        int breAtStart = bre.getValue( item.Clock );
                        ParameterEvent peBre = new ParameterEvent();
                        peBre.index = mDriver.haskyParameterIndex;
                        peBre.value = (float)(breAtStart - bre.getMinimum()) / (float)(bre.getMaximum() - bre.getMinimum());
                        q.param.add( peBre );

                        // cle
                        int cleAtStart = cle.getValue( item.Clock );
                        ParameterEvent peCle = new ParameterEvent();
                        peCle.index = mDriver.resonancParameterIndex;
                        peCle.value = (float)(cleAtStart - cle.getMinimum()) / (float)(cle.getMaximum() - cle.getMinimum());
                        q.param.add( peCle );

                        // por
                        int porAtStart = por.getValue( item.Clock );
                        ParameterEvent pePor = new ParameterEvent();
                        pePor.index = mDriver.portaTimeParameterIndex;
                        pePor.value = (float)(porAtStart - por.getMinimum()) / (float)(por.getMaximum() - por.getMinimum());
                        q.param.add( pePor );
                        #endregion
                    }

                    // ビブラート
                    // ビブラートが存在する場合、PBSは勝手に変更する。
                    if ( item.ID.VibratoHandle == null ) {
                        if ( contains_start ) {
                            // 音符頭のPIT, PBSを強制的に指定
                            int notehead_pit = pit.getValue( item.Clock );
                            MidiEvent pit0 = getPitMidiEvent( notehead_pit );
                            if ( !list.containsKey( item.Clock ) ) {
                                list.put( item.Clock, new MidiEventQueue() );
                            }
                            MidiEventQueue queue = list.get( item.Clock );
                            if ( queue.pit == null ) {
                                queue.pit = new Vector<MidiEvent>();
                            } else {
                                queue.pit.clear();
                            }
                            queue.pit.add( pit0 );
                            int notehead_pbs = pbs.getValue( item.Clock );
                            ParameterEvent pe = new ParameterEvent();
                            pe.index = mDriver.bendLblParameterIndex;
                            pe.value = notehead_pbs / 13.0f;
                            if ( queue.param == null ) {
                                queue.param = new Vector<ParameterEvent>();
                            }
                            queue.param.add( pe );
                        }
                    } else {
                        int delta_clock = 5;  //ピッチを取得するクロック間隔
                        int tempo = 120;
                        double sec_start_act = vsq.getSecFromClock( item.Clock );
                        double sec_end_act = vsq.getSecFromClock( item.Clock + item.ID.getLength() );
                        double delta_sec = delta_clock / (8.0 * tempo); //ピッチを取得する時間間隔
                        float pitmax = 0.0f;
                        int st = item.Clock;
                        if ( st < clock_start ) {
                            st = clock_start;
                        }
                        int end = item.Clock + item.ID.getLength();
                        if ( clock_end < end ) {
                            end = clock_end;
                        }
                        pit_send.add( new Point( st, end ) );
                        // ビブラートが始まるまでのピッチを取得
                        double sec_vibstart = vsq.getSecFromClock( item.Clock + item.ID.VibratoDelay );
                        int pit_count = (int)((sec_vibstart - sec_start_act) / delta_sec);
                        TreeMap<Integer, Float> pit_change = new TreeMap<Integer, Float>();
                        for ( int i = 0; i < pit_count; i++ ) {
                            double gtime = sec_start_act + delta_sec * i;
                            int clock = (int)vsq.getClockFromSec( gtime );
                            float pvalue = (float)t.getPitchAt( clock );
                            pitmax = Math.Max( pitmax, Math.Abs( pvalue ) );
                            pit_change.put( clock, pvalue );
                        }
                        // ビブラート部分のピッチを取得
                        Vector<PointD> ret = new Vector<PointD>();
                        Iterator<PointD> itr2 = new VibratoPointIteratorBySec(
                            vsq,
                            item.ID.VibratoHandle.getRateBP(),
                            item.ID.VibratoHandle.getStartRate(),
                            item.ID.VibratoHandle.getDepthBP(),
                            item.ID.VibratoHandle.getStartDepth(),
                            item.Clock + item.ID.VibratoDelay,
                            item.ID.getLength() - item.ID.VibratoDelay,
                            (float)delta_sec );
                        for ( ; itr2.hasNext(); ) {
                            PointD p = itr2.next();
                            float gtime = (float)p.getX();
                            int clock = (int)vsq.getClockFromSec( gtime );
                            float pvalue = (float)(t.getPitchAt( clock ) + p.getY() * 100.0);
                            pitmax = Math.Max( pitmax, Math.Abs( pvalue ) );
                            pit_change.put( clock, pvalue );
                        }

                        // ピッチベンドの最大値を実現するのに必要なPBS
                        int required_pbs = (int)Math.Ceiling( pitmax / 100.0 );
#if DEBUG
                        sout.println( "AquesToneRenderingRunner#generateMidiEvent; required_pbs=" + required_pbs );
#endif
                        if ( required_pbs > 13 ) {
                            required_pbs = 13;
                        }
                        if ( !list.containsKey( item.Clock ) ) {
                            list.put( item.Clock, new MidiEventQueue() );
                        }
                        MidiEventQueue queue = list.get( item.Clock );
                        ParameterEvent pe = new ParameterEvent();
                        pe.index = mDriver.bendLblParameterIndex;
                        pe.value = required_pbs / 13.0f;
                        if ( queue.param == null ) {
                            queue.param = new Vector<ParameterEvent>();
                        }
                        queue.param.add( pe );

                        // PITを順次追加
                        for ( Iterator<Integer> itr3 = pit_change.keySet().iterator(); itr3.hasNext(); ) {
                            Integer clock = itr3.next();
                            if ( clock_start <= clock && clock <= clock_end ) {
                                float pvalue = pit_change.get( clock );
                                int pit_value = (int)(8192.0 / (double)required_pbs * pvalue / 100.0);
                                if ( !list.containsKey( clock ) ) {
                                    list.put( clock, new MidiEventQueue() );
                                }
                                MidiEventQueue q = list.get( clock );
                                MidiEvent me = getPitMidiEvent( pit_value );
                                if ( q.pit == null ) {
                                    q.pit = new Vector<MidiEvent>();
                                } else {
                                    q.pit.clear();
                                }
                                q.pit.add( me );
                            } else if ( clock_end < clock ) {
                                break;
                            }
                        }
                    }

                    //pit_send.add( pit_send_p );

                    // noteoff MIDIイベントを作成
                    if ( contains_end ) {
                        MidiEvent noteoff = new MidiEvent();
                        noteoff.firstByte = 0x80;
                        noteoff.data = new int[] { item.ID.Note, 0x40 }; // ここのvel
                        Vector<MidiEvent> a_noteoff = Arrays.asList( new MidiEvent[] { noteoff } );
                        if ( !list.containsKey( endclock ) ) {
                            list.put( endclock, new MidiEventQueue() );
                        }
                        MidiEventQueue q = list.get( endclock );
                        if ( q.noteoff == null ) {
                            q.noteoff = new Vector<MidiEvent>();
                        }
                        q.noteoff.addAll( a_noteoff );
                        pit_send.add( new Point( endclock, endclock ) ); // PITの送信を抑制するために必要
                    }
                }

                if ( clock_end < item.Clock ) {
                    break;
                }
            }

            // pitch bend sensitivity
            // RPNで送信するのが上手くいかないので、parameterを直接いぢる
            if ( pbs != null ) {
                int keycount = pbs.size();
                for ( int i = 0; i < keycount; i++ ) {
                    int clock = pbs.getKeyClock( i );
                    if ( clock_start <= clock && clock <= clock_end ) {
                        int value = pbs.getElementA( i );
                        ParameterEvent pbse = new ParameterEvent();
                        pbse.index = mDriver.bendLblParameterIndex;
                        pbse.value = value / 13.0f;
                        MidiEventQueue queue = null;
                        if ( list.containsKey( clock ) ) {
                            queue = list.get( clock );
                        } else {
                            queue = new MidiEventQueue();
                        }
                        if ( queue.param == null ) {
                            queue.param = new Vector<ParameterEvent>();
                        }
                        queue.param.add( pbse );
                        list.put( clock, queue );
                    } else if ( clock_end < clock ) {
                        break;
                    }
                }
            }

            // pitch bend
            if ( pit != null ) {
                int keycount = pit.size();
                for ( int i = 0; i < keycount; i++ ) {
                    int clock = pit.getKeyClock( i );
                    if ( clock_start <= clock && clock <= clock_end ) {
                        boolean contains = false;
                        for ( Iterator<Point> itr = pit_send.iterator(); itr.hasNext(); ) {
                            Point p = itr.next();
                            if ( p.x <= clock && clock <= p.y ) {
                                contains = true;
                                break;
                            }
                        }
                        if ( contains ) {
                            continue;
                        }
                        int value = pit.getElementA( i );
                        MidiEvent pbs0 = getPitMidiEvent( value );
                        MidiEventQueue queue = null;
                        if ( list.containsKey( clock ) ) {
                            queue = list.get( clock );
                        } else {
                            queue = new MidiEventQueue();
                        }
                        if ( queue.pit == null ) {
                            queue.pit = new Vector<MidiEvent>();
                        } else {
                            queue.pit.clear();
                        }
                        queue.pit.add( pbs0 );
                        list.put( clock, queue );
                    } else if ( clock_end < clock ) {
                        break;
                    }
                }
            }

            appendParameterEvents( list, dyn, mDriver.volumeParameterIndex, clock_start, clock_end );
            appendParameterEvents( list, bre, mDriver.haskyParameterIndex, clock_start, clock_end );
            appendParameterEvents( list, cle, mDriver.resonancParameterIndex, clock_start, clock_end );
            appendParameterEvents( list, por, mDriver.portaTimeParameterIndex, clock_start, clock_end );

            return list;
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="vsq"></param>
        /// <param name="track"></param>
        /// <param name="clock_start"></param>
        /// <param name="clock_end"></param>
        /// <returns></returns>
        protected override EventQueueSequence generateMidiEvent(VsqFileEx vsq, int track, int clock_start, int clock_end)
        {
            EventQueueSequence list = new EventQueueSequence();
            VsqTrack           t    = vsq.Track.get(track);

            addSingerEvents(list, t, clock_start, clock_end);

            // ノートon, off
            Vector <Point> pit_send = new Vector <Point>(); // PITが追加されたゲートタイム。音符先頭の分を重複して送信するのを回避するために必要。
            VsqBPList      pit      = t.getCurve("pit");
            VsqBPList      pbs      = t.getCurve("pbs");
            VsqBPList      dyn      = t.getCurve("dyn");
            VsqBPList      bre      = t.getCurve("bre");
            VsqBPList      cle      = t.getCurve("cle");
            VsqBPList      por      = t.getCurve("por");

            for (Iterator <VsqEvent> itr = t.getNoteEventIterator(); itr.hasNext();)
            {
                VsqEvent item           = itr.next();
                int      endclock       = item.Clock + item.ID.getLength();
                boolean  contains_start = clock_start <= item.Clock && item.Clock <= clock_end;
                boolean  contains_end   = clock_start <= endclock && endclock <= clock_end;
                if (contains_start || contains_end)
                {
                    if (contains_start)
                    {
                        #region contains_start
                        // noteonのゲートタイムが,範囲に入っている
                        // noteon MIDIイベントを作成

                        MidiEvent[] noteOnEvents = mDriver.createNoteOnEvent(item.ID.Note, item.ID.Dynamics, item.ID.LyricHandle.L0.Phrase);
                        if (noteOnEvents.Length > 0)
                        {
                            MidiEventQueue queue = list.get(item.Clock);

                            Vector <MidiEvent> add = Arrays.asList(noteOnEvents);
                            queue.noteon.addAll(add);
                            pit_send.add(new Point(item.Clock, item.Clock));
                        }

                        /* 音符頭で設定するパラメータ */
                        // Release
                        MidiEventQueue q = list.get(item.Clock);

                        String strRelease = VsqFileEx.getEventTag(item, VsqFileEx.TAG_VSQEVENT_AQUESTONE_RELEASE);
                        int    release    = 64;
                        try {
                            release = int.Parse(strRelease);
                        } catch (Exception ex) {
                            Logger.write(typeof(AquesToneWaveGenerator) + ".generateMidiEvent; ex=" + ex + "\n");
                            release = 64;
                        }
                        ParameterEvent pe = new ParameterEvent();
                        pe.index = mDriver.releaseParameterIndex;
                        pe.value = release / 127.0f;
                        q.param.add(pe);

                        // dyn
                        int            dynAtStart = dyn.getValue(item.Clock);
                        ParameterEvent peDyn      = new ParameterEvent();
                        peDyn.index = mDriver.volumeParameterIndex;
                        peDyn.value = (float)(dynAtStart - dyn.getMinimum()) / (float)(dyn.getMaximum() - dyn.getMinimum());
                        q.param.add(peDyn);

                        // bre
                        int            breAtStart = bre.getValue(item.Clock);
                        ParameterEvent peBre      = new ParameterEvent();
                        peBre.index = mDriver.haskyParameterIndex;
                        peBre.value = (float)(breAtStart - bre.getMinimum()) / (float)(bre.getMaximum() - bre.getMinimum());
                        q.param.add(peBre);

                        // cle
                        int            cleAtStart = cle.getValue(item.Clock);
                        ParameterEvent peCle      = new ParameterEvent();
                        peCle.index = mDriver.resonancParameterIndex;
                        peCle.value = (float)(cleAtStart - cle.getMinimum()) / (float)(cle.getMaximum() - cle.getMinimum());
                        q.param.add(peCle);

                        // por
                        int            porAtStart = por.getValue(item.Clock);
                        ParameterEvent pePor      = new ParameterEvent();
                        pePor.index = mDriver.portaTimeParameterIndex;
                        pePor.value = (float)(porAtStart - por.getMinimum()) / (float)(por.getMaximum() - por.getMinimum());
                        q.param.add(pePor);
                        #endregion
                    }

                    // ビブラート
                    // ビブラートが存在する場合、PBSは勝手に変更する。
                    if (item.ID.VibratoHandle == null)
                    {
                        if (contains_start)
                        {
                            // 音符頭のPIT, PBSを強制的に指定
                            int            notehead_pit = pit.getValue(item.Clock);
                            MidiEvent      pit0         = getPitMidiEvent(notehead_pit);
                            MidiEventQueue queue        = list.get(item.Clock);
                            queue.pit.clear();
                            queue.pit.add(pit0);
                            int            notehead_pbs = pbs.getValue(item.Clock);
                            ParameterEvent pe           = new ParameterEvent();
                            pe.index = mDriver.bendLblParameterIndex;
                            pe.value = notehead_pbs / 13.0f;
                            queue.param.add(pe);
                        }
                    }
                    else
                    {
                        int    delta_clock   = 5; //ピッチを取得するクロック間隔
                        int    tempo         = 120;
                        double sec_start_act = vsq.getSecFromClock(item.Clock);
                        double sec_end_act   = vsq.getSecFromClock(item.Clock + item.ID.getLength());
                        double delta_sec     = delta_clock / (8.0 * tempo); //ピッチを取得する時間間隔
                        float  pitmax        = 0.0f;
                        int    st            = item.Clock;
                        if (st < clock_start)
                        {
                            st = clock_start;
                        }
                        int end = item.Clock + item.ID.getLength();
                        if (clock_end < end)
                        {
                            end = clock_end;
                        }
                        pit_send.add(new Point(st, end));
                        // ビブラートが始まるまでのピッチを取得
                        double sec_vibstart = vsq.getSecFromClock(item.Clock + item.ID.VibratoDelay);
                        int    pit_count    = (int)((sec_vibstart - sec_start_act) / delta_sec);
                        TreeMap <Integer, Float> pit_change = new TreeMap <Integer, Float>();
                        for (int i = 0; i < pit_count; i++)
                        {
                            double gtime  = sec_start_act + delta_sec * i;
                            int    clock  = (int)vsq.getClockFromSec(gtime);
                            float  pvalue = (float)t.getPitchAt(clock);
                            pitmax = Math.Max(pitmax, Math.Abs(pvalue));
                            pit_change.put(clock, pvalue);
                        }
                        // ビブラート部分のピッチを取得
                        Vector <PointD>   ret  = new Vector <PointD>();
                        Iterator <PointD> itr2 = new VibratoPointIteratorBySec(
                            vsq,
                            item.ID.VibratoHandle.getRateBP(),
                            item.ID.VibratoHandle.getStartRate(),
                            item.ID.VibratoHandle.getDepthBP(),
                            item.ID.VibratoHandle.getStartDepth(),
                            item.Clock + item.ID.VibratoDelay,
                            item.ID.getLength() - item.ID.VibratoDelay,
                            (float)delta_sec);
                        for ( ; itr2.hasNext();)
                        {
                            PointD p      = itr2.next();
                            float  gtime  = (float)p.getX();
                            int    clock  = (int)vsq.getClockFromSec(gtime);
                            float  pvalue = (float)(t.getPitchAt(clock) + p.getY() * 100.0);
                            pitmax = Math.Max(pitmax, Math.Abs(pvalue));
                            pit_change.put(clock, pvalue);
                        }

                        // ピッチベンドの最大値を実現するのに必要なPBS
                        int required_pbs = (int)Math.Ceiling(pitmax / 100.0);
#if DEBUG
                        sout.println("AquesToneRenderingRunner#generateMidiEvent; required_pbs=" + required_pbs);
#endif
                        if (required_pbs > 13)
                        {
                            required_pbs = 13;
                        }
                        MidiEventQueue queue = list.get(item.Clock);
                        ParameterEvent pe    = new ParameterEvent();
                        pe.index = mDriver.bendLblParameterIndex;
                        pe.value = required_pbs / 13.0f;
                        queue.param.add(pe);

                        // PITを順次追加
                        for (Iterator <Integer> itr3 = pit_change.keySet().iterator(); itr3.hasNext();)
                        {
                            Integer clock = itr3.next();
                            if (clock_start <= clock && clock <= clock_end)
                            {
                                float          pvalue    = pit_change.get(clock);
                                int            pit_value = (int)(8192.0 / (double)required_pbs * pvalue / 100.0);
                                MidiEventQueue q         = list.get(clock);
                                MidiEvent      me        = getPitMidiEvent(pit_value);
                                q.pit.clear();
                                q.pit.add(me);
                            }
                            else if (clock_end < clock)
                            {
                                break;
                            }
                        }
                    }

                    //pit_send.add( pit_send_p );

                    // noteoff MIDIイベントを作成
                    if (contains_end)
                    {
                        MidiEvent noteoff = new MidiEvent();
                        noteoff.firstByte = 0x80;
                        noteoff.data      = new int[] { item.ID.Note, 0x40 }; // ここのvel
                        Vector <MidiEvent> a_noteoff = Arrays.asList(new MidiEvent[] { noteoff });
                        MidiEventQueue     q         = list.get(endclock);
                        q.noteoff.addAll(a_noteoff);
                        pit_send.add(new Point(endclock, endclock));     // PITの送信を抑制するために必要
                    }
                }

                if (clock_end < item.Clock)
                {
                    break;
                }
            }

            // pitch bend sensitivity
            // RPNで送信するのが上手くいかないので、parameterを直接いぢる
            if (pbs != null)
            {
                int keycount = pbs.size();
                for (int i = 0; i < keycount; i++)
                {
                    int clock = pbs.getKeyClock(i);
                    if (clock_start <= clock && clock <= clock_end)
                    {
                        int            value = pbs.getElementA(i);
                        ParameterEvent pbse  = new ParameterEvent();
                        pbse.index = mDriver.bendLblParameterIndex;
                        pbse.value = value / 13.0f;
                        MidiEventQueue queue = list.get(clock);
                        queue.param.add(pbse);
                    }
                    else if (clock_end < clock)
                    {
                        break;
                    }
                }
            }

            // pitch bend
            if (pit != null)
            {
                int keycount = pit.size();
                for (int i = 0; i < keycount; i++)
                {
                    int clock = pit.getKeyClock(i);
                    if (clock_start <= clock && clock <= clock_end)
                    {
                        boolean contains = false;
                        for (Iterator <Point> itr = pit_send.iterator(); itr.hasNext();)
                        {
                            Point p = itr.next();
                            if (p.x <= clock && clock <= p.y)
                            {
                                contains = true;
                                break;
                            }
                        }
                        if (contains)
                        {
                            continue;
                        }
                        int            value = pit.getElementA(i);
                        MidiEvent      pbs0  = getPitMidiEvent(value);
                        MidiEventQueue queue = list.get(clock);
                        queue.pit.clear();
                        queue.pit.add(pbs0);
                    }
                    else if (clock_end < clock)
                    {
                        break;
                    }
                }
            }

            appendParameterEvents(list, dyn, mDriver.volumeParameterIndex, clock_start, clock_end);
            appendParameterEvents(list, bre, mDriver.haskyParameterIndex, clock_start, clock_end);
            appendParameterEvents(list, cle, mDriver.resonancParameterIndex, clock_start, clock_end);
            appendParameterEvents(list, por, mDriver.portaTimeParameterIndex, clock_start, clock_end);

            return(list);
        }