Exemple #1
0
        public VibratoPointIteratorBySec(VsqFileEx vsq,
                                         VibratoBPList rate,
                                         int start_rate,
                                         VibratoBPList depth,
                                         int start_depth,
                                         int clock_start,
                                         int clock_width,
                                         float sec_resolution)
        {
            this.vsq            = vsq;
            this.rate           = rate;
            this.start_rate     = start_rate;
            this.depth          = depth;
            this.start_depth    = start_depth;
            this.clock_start    = clock_start;
            this.clock_width    = clock_width;
            this.sec_resolution = sec_resolution;

            sec0        = vsq.getSecFromClock(clock_start);
            sec1        = vsq.getSecFromClock(clock_start + clock_width);
            count       = (int)((sec1 - sec0) / sec_resolution);
            phase       = 0;
            start_rate  = rate.getValue(0.0f, start_rate);
            start_depth = depth.getValue(0.0f, start_depth);
            amplitude   = start_depth * 2.5f / 127.0f / 2.0f; // ビブラートの振幅。
            period      = getPeriodFromRate(start_rate);      //ビブラートの周期、秒
            omega       = (float)(2.0 * Math.PI / period);    // 角速度(rad/sec)
            sec         = sec0;
            fadewidth   = (float)(sec1 - sec0) * 0.2f;
        }
Exemple #2
0
        /// <summary>
        /// vsqファイルのstart_clockクロックからメトロノームを起動する。startは、start_clockをいつから起動したかを指定する。
        /// </summary>
        /// <param name="vsq"></param>
        /// <param name="start_clock"></param>
        /// <param name="start"></param>
        public static void Start(VsqFileEx vsq, int start_clock, double start_time)
        {
            s_queue.clear();
            m_stop_required           = false;
            m_stop_metronome_required = false;
            if (s_device0 == null)
            {
                s_device0 = new MidiDeviceImp(s_metronome_device);
            }
            if (s_metronome_device != s_general_device)
            {
                if (s_device1 == null)
                {
                    s_device1 = new MidiDeviceImp(s_general_device);
                }
            }

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

            m_started       = start_time;
            m_started_clock = start_clock;
            m_temp_exit     = false;

            for (int track = 1; track < m_vsq.Track.size(); track++)
            {
#if DEBUG
                AppManager.debugWriteLine("Metronome.Start; track=" + track);
#endif
                for (Iterator <VsqEvent> itr = m_vsq.Track.get(track).getNoteEventIterator(); itr.hasNext();)
                {
                    VsqEvent item = itr.next();
                    if (start_clock <= item.Clock)
                    {
                        MidiQueue q = new MidiQueue();
                        q.Track    = track;
                        q.Channel  = (byte)(track - 1);
                        q.Clock    = item.Clock;
                        q.Note     = (byte)(item.ID.Note);
                        q.Program  = 0;
                        q.Velocity = 0x40;
                        q.Done    += new MidiQueueDoneEventHandler(ReGenerateMidiQueue);
                        s_queue.add(q);
                        break;
                    }
                }
            }

            Collections.sort(s_queue);

            m_thread = new Thread(new ThreadStart(ThreadProc));
            m_thread.IsBackground = true;
            m_thread.Priority     = ThreadPriority.Highest;
            m_thread.Start();
        }
        /// <summary>
        /// 初期化メソッド
        /// </summary>
        /// <param name="parameter"></param>
        public void init(VsqFileEx vsq, int track, int start_clock, int end_clock, int sample_rate)
        {
            getDriver().setSampleRate(sample_rate);
            mTrack      = track;
            mStartClock = start_clock;
            mEndClock   = end_clock;
            mSampleRate = sample_rate;

            this.mVsq = (VsqFileEx)vsq.clone();
            this.mVsq.updateTotalClocks();

            if (mEndClock < this.mVsq.TotalClocks)
            {
                this.mVsq.removePart(mEndClock, this.mVsq.TotalClocks + 480);
            }

            double end_sec   = mVsq.getSecFromClock(start_clock);
            double start_sec = mVsq.getSecFromClock(end_clock);

            double trim_sec = 0.0; // レンダリング結果から省かなければならない秒数。

            if (mStartClock < this.mVsq.getPreMeasureClocks())
            {
                trim_sec = this.mVsq.getSecFromClock(mStartClock);
            }
            else
            {
                this.mVsq.removePart(mVsq.getPreMeasureClocks(), mStartClock);
                trim_sec = this.mVsq.getSecFromClock(this.mVsq.getPreMeasureClocks());
            }
            this.mVsq.updateTotalClocks();

            mTrimRemain = (int)(trim_sec * mSampleRate);
            //mTrimRemain = 0;
#if DEBUG
            sout.println("AeuqsToneWaveGenerator#init; mTrimRemain=" + mTrimRemain);
#endif
        }
        public void begin(long total_samples, WorkerState state)
        {
            is_running_    = true;
            total_samples_ = total_samples;
            int buffer_length = sample_rate_ / 10;

            double[] left  = new double[buffer_length];
            double[] right = new double[buffer_length];

            if (driver_.getUi(null) == null)
            {
                throw new InvalidOperationException("plugin ui を main view のスレッドで作成した後、このメソッドを呼ばなくてはならない。");
            }

            var eventQueue = generateMidiEvent(sequence_, track_index_);

            foreach (var sequence_item in eventQueue.getSequence())
            {
                var clock = sequence_item.Key;
                var queue = sequence_item.Value;

                long to_sample = (long)(sequence_.getSecFromClock(clock) * sample_rate_);
                if (to_sample >= total_samples_)
                {
                    to_sample = total_samples_;
                }
                doSynthesis(to_sample, left, right, state);
                if (position_ >= total_samples_)
                {
                    break;
                }

                // noteOff, noteOn の順に分けて send する方法も考えられるが、正しく動作しない。
                // このため、いったん一つの配列にまとめてから send する必要がある。
                var events = new List <MidiEvent>();
                events.AddRange(queue.pit);
                events.AddRange(queue.noteoff);
                events.AddRange(queue.noteon);
                driver_.send(events.ToArray());

                //TODO: のこりのイベント送る処理
            }

            doSynthesis(total_samples, left, right, state);

            receiver_.end();
            is_running_ = false;
            state.reportComplete();
        }
        public void begin(long total_samples, WorkerState state)
        {
            var mDriver = getDriver();

#if DEBUG
            sout.println("AquesToneRenderingRunner#begin; (mDriver==null)=" + (mDriver == null));
            String file = System.IO.Path.Combine(System.Windows.Forms.Application.StartupPath, "AquesToneWaveGenerator.txt");
            log           = new System.IO.StreamWriter(file);
            log.AutoFlush = true;
#endif
            if (mDriver == null)
            {
#if DEBUG
                log.WriteLine("mDriver==null");
                log.Close();
#endif
                exitBegin();
                state.reportComplete();
                return;
            }

#if DEBUG
            sout.println("AquesToneRenderingRunner#begin; mDriver.loaded=" + mDriver.loaded);
#endif
            if (!mDriver.loaded)
            {
#if DEBUG
                log.WriteLine("mDriver.loaded=" + mDriver.loaded);
                log.Close();
#endif
                exitBegin();
                state.reportComplete();
                return;
            }

            mRunning = true;
            //mAbortRequired = false;
            mTotalSamples = total_samples;
#if DEBUG
            sout.println("AquesToneWaveGenerator#begin; mTotalSamples=" + mTotalSamples);
            log.WriteLine("mTotalSamples=" + mTotalSamples);
            log.WriteLine("mTrimRemain=" + mTrimRemain);
#endif

            VsqTrack track       = mVsq.Track.get(mTrack);
            int      BUFLEN      = mSampleRate / 10;
            double[] left        = new double[BUFLEN];
            double[] right       = new double[BUFLEN];
            long     saProcessed = 0;
            int      saRemain    = 0;
            int      lastClock   = 0; // 最後に処理されたゲートタイム

            // 最初にダミーの音を鳴らす
            // (最初に入るノイズを回避するためと、前回途中で再生停止した場合に無音から始まるようにするため)
            mDriver.resetAllParameters();
            mDriver.process(left, right, BUFLEN);
            MidiEvent f_noteon = new MidiEvent();
            f_noteon.firstByte = 0x90;
            f_noteon.data      = new int[] { 0x40, 0x40 };
            f_noteon.clock     = 0;
            mDriver.send(new MidiEvent[] { f_noteon });
            mDriver.process(left, right, BUFLEN);
            MidiEvent f_noteoff = new MidiEvent();
            f_noteoff.firstByte = 0x80;
            f_noteoff.data      = new int[] { 0x40, 0x7F };
            mDriver.send(new MidiEvent[] { f_noteoff });
            for (int i = 0; i < 3; i++)
            {
                mDriver.process(left, right, BUFLEN);
            }
#if DEBUG
            log.WriteLine("pre-process done");
            log.WriteLine("-----------------------------------------------------");
            VsqTrack vsq_track = mVsq.Track.get(mTrack);
            for (Iterator <VsqEvent> itr = vsq_track.getNoteEventIterator(); itr.hasNext();)
            {
                VsqEvent item = itr.next();
                log.WriteLine("c" + item.Clock + "; " + item.ID.LyricHandle.L0.Phrase);
            }
#endif

            // レンダリング開始位置での、パラメータの値をセットしておく
            for (Iterator <VsqEvent> itr = track.getNoteEventIterator(); itr.hasNext();)
            {
                VsqEvent item = itr.next();
#if DEBUG
                sout.println("AquesToneWaveGenerator#begin; item.Clock=" + item.Clock);
                log.WriteLine("*********************************************************");
                log.WriteLine("item.Clock=" + item.Clock);
#endif
                long saNoteStart = (long)(mVsq.getSecFromClock(item.Clock) * mSampleRate);
                long saNoteEnd   = (long)(mVsq.getSecFromClock(item.Clock + item.ID.getLength()) * mSampleRate);
#if DEBUG
                log.WriteLine("saNoteStart=" + saNoteStart + "; saNoteEnd=" + saNoteEnd);
#endif

                EventQueueSequence list = generateMidiEvent(mVsq, mTrack, lastClock, item.Clock + item.ID.getLength());
                lastClock = item.Clock + item.ID.Length + 1;
                for (Iterator <Integer> itr2 = list.keyIterator(); itr2.hasNext();)
                {
                    // まず直前までの分を合成
                    Integer clock = itr2.next();
#if DEBUG
                    log.WriteLine("-------------------------------------------------------");
                    sout.println("AquesToneWaveGenerator#begin;     clock=" + clock);
#endif
                    long saStart = (long)(mVsq.getSecFromClock(clock) * mSampleRate);
                    saRemain = (int)(saStart - saProcessed);
#if DEBUG
                    log.WriteLine("saStart=" + saStart);
                    log.WriteLine("saRemain=" + saRemain);
#endif
                    while (saRemain > 0)
                    {
                        if (state.isCancelRequested())
                        {
                            goto heaven;
                        }
                        int len = saRemain > BUFLEN ? BUFLEN : saRemain;
                        mDriver.process(left, right, len);
                        waveIncoming(left, right, len);
                        saRemain    -= len;
                        saProcessed += len;
                        state.reportProgress(saProcessed);
                        //mTotalAppend += len; <- waveIncomingで計算されるので
                    }

                    // MIDiイベントを送信
                    MidiEventQueue queue = list.get(clock);
                    // まずnoteoff
                    boolean noteoff_send = false;
                    if (queue.noteoff.size() > 0)
                    {
#if DEBUG
                        for (int i = 0; i < queue.noteoff.size(); i++)
                        {
                            String    str   = "";
                            MidiEvent itemi = queue.noteoff.get(i);
                            str += "0x" + PortUtil.toHexString(itemi.firstByte, 2) + " ";
                            for (int j = 0; j < itemi.data.Length; j++)
                            {
                                str += "0x" + PortUtil.toHexString(itemi.data[j], 2) + " ";
                            }
                            sout.println(typeof(AquesToneWaveGenerator) + "#begin;         noteoff; " + str);
                        }
#endif
                        mDriver.send(queue.noteoff.toArray(new MidiEvent[] { }));
                        noteoff_send = true;
                    }
                    // parameterの変更
                    if (queue.param.size() > 0)
                    {
                        for (Iterator <ParameterEvent> itr3 = queue.param.iterator(); itr3.hasNext();)
                        {
                            ParameterEvent pe = itr3.next();
#if DEBUG
                            sout.println(typeof(AquesToneWaveGenerator) + "#begin;         param;   index=" + pe.index + "; value=" + pe.value);
#endif
                            mDriver.setParameter(pe.index, pe.value);
                        }
                    }
                    // ついでnoteon
                    if (queue.noteon.size() > 0)
                    {
                        // 同ゲートタイムにピッチベンドも指定されている場合、同時に送信しないと反映されないようだ!
                        if (queue.pit.size() > 0)
                        {
                            queue.noteon.addAll(queue.pit);
                            queue.pit.clear();
                        }
#if DEBUG
                        for (int i = 0; i < queue.noteon.size(); i++)
                        {
                            String    str   = "";
                            MidiEvent itemi = queue.noteon.get(i);
                            str += "0x" + PortUtil.toHexString(itemi.firstByte, 2) + " ";
                            for (int j = 0; j < itemi.data.Length; j++)
                            {
                                str += "0x" + PortUtil.toHexString(itemi.data[j], 2) + " ";
                            }
                            sout.println(typeof(AquesToneWaveGenerator) + "#begin;         noteon;  " + str);
                        }
#endif
                        mDriver.send(queue.noteon.toArray(new MidiEvent[] { }));
                    }
                    // PIT
                    if (queue.pit.size() > 0 && !noteoff_send)
                    {
#if DEBUG
                        for (int i = 0; i < queue.pit.size(); i++)
                        {
                            String    str   = "";
                            MidiEvent itemi = queue.pit.get(i);
                            str += "0x" + PortUtil.toHexString(itemi.firstByte, 2) + " ";
                            for (int j = 0; j < itemi.data.Length; j++)
                            {
                                str += "0x" + PortUtil.toHexString(itemi.data[j], 2) + " ";
                            }
                            sout.println(typeof(AquesToneWaveGenerator) + "#begin;         pit;     " + str);
                        }
#endif
                        mDriver.send(queue.pit.toArray(new MidiEvent[] { }));
                    }
                    if (mDriver.getUi(mMainWindow) != null)
                    {
                        mDriver.getUi(mMainWindow).invalidateUi();
                    }
                }
            }

            // totalSamplesに足りなかったら、追加してレンダリング
            saRemain = (int)(mTotalSamples - mTotalAppend);
#if DEBUG
            sout.println("AquesToneRenderingRunner#run; totalSamples=" + mTotalSamples + "; mTotalAppend=" + mTotalAppend + "; saRemain=" + saRemain);
#endif
            while (saRemain > 0)
            {
                if (state.isCancelRequested())
                {
                    goto heaven;
                }
                int len = saRemain > BUFLEN ? BUFLEN : saRemain;
                mDriver.process(left, right, len);
                waveIncoming(left, right, len);
                saRemain    -= len;
                saProcessed += len;
                state.reportProgress(saProcessed);
                //mTotalAppend += len;
            }
heaven:
#if DEBUG
            log.Close();
#endif
            exitBegin();
            state.reportComplete();
        }
        public static void GenerateSinglePhone(int note, string singer, string file, double amp)
        {
            string renderer = "";

            SingerConfig[] singers1             = VocaloSysUtil.getSingerConfigs(SynthesizerType.VOCALOID1);
            int            c                    = singers1.Length;
            string         first_found_singer   = "";
            string         first_found_renderer = "";

            for (int i = 0; i < c; i++)
            {
                if (first_found_singer.Equals(""))
                {
                    first_found_singer   = singers1[i].VOICENAME;
                    first_found_renderer = VsqFileEx.RENDERER_DSB2;
                }
                if (singers1[i].VOICENAME.Equals(singer))
                {
                    renderer = VsqFileEx.RENDERER_DSB2;
                    break;
                }
            }

            SingerConfig[] singers2 = VocaloSysUtil.getSingerConfigs(SynthesizerType.VOCALOID2);
            c = singers2.Length;
            for (int i = 0; i < c; i++)
            {
                if (first_found_singer.Equals(""))
                {
                    first_found_singer   = singers2[i].VOICENAME;
                    first_found_renderer = VsqFileEx.RENDERER_DSB3;
                }
                if (singers2[i].VOICENAME.Equals(singer))
                {
                    renderer = VsqFileEx.RENDERER_DSB3;
                    break;
                }
            }

            foreach (var sc in AppManager.editorConfig.UtauSingers)
            {
                if (first_found_singer.Equals(""))
                {
                    first_found_singer   = sc.VOICENAME;
                    first_found_renderer = VsqFileEx.RENDERER_UTU0;
                }
                if (sc.VOICENAME.Equals(singer))
                {
                    renderer = VsqFileEx.RENDERER_UTU0;
                    break;
                }
            }

            VsqFileEx vsq = new VsqFileEx(singer, 1, 4, 4, 500000);

            if (renderer.Equals(""))
            {
                singer   = first_found_singer;
                renderer = first_found_renderer;
            }
            vsq.Track[1].getCommon().Version = renderer;
            VsqEvent item = new VsqEvent(1920, new VsqID(0));

            item.ID.LyricHandle = new LyricHandle("あ", "a");
            item.ID.setLength(480);
            item.ID.Note          = note;
            item.ID.VibratoHandle = null;
            item.ID.type          = VsqIDType.Anote;
            vsq.Track[1].addEvent(item);
            vsq.updateTotalClocks();
            int    ms_presend = 500;
            string tempdir    = Path.Combine(AppManager.getCadenciiTempDir(), AppManager.getID());

            if (!Directory.Exists(tempdir))
            {
                try {
                    PortUtil.createDirectory(tempdir);
                } catch (Exception ex) {
                    Logger.write(typeof(FormGenerateKeySound) + ".GenerateSinglePhone; ex=" + ex + "\n");
                    serr.println("Program#GenerateSinglePhone; ex=" + ex);
                    return;
                }
            }
            WaveWriter ww = null;

            try {
                ww = new WaveWriter(file);
                RendererKind     kind        = VsqFileEx.getTrackRendererKind(vsq.Track[1]);
                WaveGenerator    generator   = VSTiDllManager.getWaveGenerator(kind);
                int              sample_rate = vsq.config.SamplingRate;
                FileWaveReceiver receiver    = new FileWaveReceiver(file, 1, 16, sample_rate);
                generator.setReceiver(receiver);
                generator.setGlobalConfig(AppManager.editorConfig);
#if DEBUG
                sout.println("FormGenerateKeySound#GenerateSinglePhone; sample_rate=" + sample_rate);
#endif
                generator.init(vsq, 1, 0, vsq.TotalClocks, sample_rate);
                double         total_sec = vsq.getSecFromClock(vsq.TotalClocks) + 1.0;
                WorkerStateImp state     = new WorkerStateImp();
                generator.begin((long)(total_sec * sample_rate), state);
            } catch (Exception ex) {
                serr.println("FormGenerateKeySound#GenerateSinglePhone; ex=" + ex);
                Logger.write(typeof(FormGenerateKeySound) + ".GenerateSinglePhone; ex=" + ex + "\n");
            } finally {
                if (ww != null)
                {
                    try {
                        ww.close();
                    } catch (Exception ex2) {
                        Logger.write(typeof(FormGenerateKeySound) + ".GenerateSinglePhone; ex=" + ex2 + "\n");
                        serr.println("FormGenerateKeySound#GenerateSinglePhone; ex2=" + ex2);
                    }
                }
            }
        }
        /// <summary>
        /// 初期化メソッド
        /// </summary>
        /// <param name="parameter"></param>
        public void init( VsqFileEx vsq, int track, int start_clock, int end_clock, int sample_rate )
        {
            getDriver().setSampleRate( sample_rate );
            mTrack = track;
            mStartClock = start_clock;
            mEndClock = end_clock;
            mSampleRate = sample_rate;

            this.mVsq = (VsqFileEx)vsq.clone();
            this.mVsq.updateTotalClocks();

            if ( mEndClock < this.mVsq.TotalClocks ) {
                this.mVsq.removePart( mEndClock, this.mVsq.TotalClocks + 480 );
            }

            double end_sec = mVsq.getSecFromClock( start_clock );
            double start_sec = mVsq.getSecFromClock( end_clock );

            double trim_sec = 0.0; // レンダリング結果から省かなければならない秒数。
            if ( mStartClock < this.mVsq.getPreMeasureClocks() ) {
                trim_sec = this.mVsq.getSecFromClock( mStartClock );
            } else {
                this.mVsq.removePart( mVsq.getPreMeasureClocks(), mStartClock );
                trim_sec = this.mVsq.getSecFromClock( this.mVsq.getPreMeasureClocks() );
            }
            this.mVsq.updateTotalClocks();

            mTrimRemain = (int)(trim_sec * mSampleRate);
            //mTrimRemain = 0;
#if DEBUG
            sout.println( "AeuqsToneWaveGenerator#init; mTrimRemain=" + mTrimRemain );
#endif
        }
        /*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;
        }
Exemple #10
0
        /// <summary>
        /// vsqファイルのstart_clockクロックからメトロノームを起動する。startは、start_clockをいつから起動したかを指定する。
        /// </summary>
        /// <param name="vsq"></param>
        /// <param name="start_clock"></param>
        /// <param name="start"></param>
        public static void Start( VsqFileEx vsq, int start_clock, double start_time ) {
            s_queue.clear();
            m_stop_required = false;
            m_stop_metronome_required = false;
            if ( s_device0 == null ) {
                s_device0 = new MidiDeviceImp( s_metronome_device );
            }
            if ( s_metronome_device != s_general_device ) {
                if ( s_device1 == null ) {
                    s_device1 = new MidiDeviceImp( s_general_device );
                }
            }

            m_vsq = (VsqFileEx)vsq.clone();
            m_started_sec = m_vsq.getSecFromClock( start_clock );
            ByRef<Integer> bar = new ByRef<Integer>();
            Timesig timesig = m_vsq.getTimesigAt( start_clock, bar );
            int clock_at_bartop = m_vsq.getClockFromBarCount( bar.value );
            int clock_step = 480 * 4 / timesig.denominator;
            int next_clock = clock_at_bartop + ((start_clock - clock_at_bartop) / clock_step + 1) * clock_step;
            m_started = start_time;
            m_started_clock = start_clock;
            m_temp_exit = false;

            for ( int track = 1; track < m_vsq.Track.size(); track++ ) {
#if DEBUG
                AppManager.debugWriteLine( "Metronome.Start; track=" + track );
#endif
                for ( Iterator<VsqEvent> itr = m_vsq.Track.get( track ).getNoteEventIterator(); itr.hasNext(); ) {
                    VsqEvent item = itr.next();
                    if ( start_clock <= item.Clock ) {
                        MidiQueue q = new MidiQueue();
                        q.Track = track;
                        q.Channel = (byte)(track - 1);
                        q.Clock = item.Clock;
                        q.Note = (byte)(item.ID.Note);
                        q.Program = 0;
                        q.Velocity = 0x40;
                        q.Done += new MidiQueueDoneEventHandler( ReGenerateMidiQueue );
                        s_queue.add( q );
                        break;
                    }
                }
            }

            Collections.sort( s_queue );

            m_thread = new Thread( new ThreadStart( ThreadProc ) );
            m_thread.IsBackground = true;
            m_thread.Priority = ThreadPriority.Highest;
            m_thread.Start();
        }
        public void patchWork(WorkerState state, Object arg)
        {
#if DEBUG
            sout.println("SynthesizeWorker#patchWork");
#endif
            VsqFileEx             vsq    = AppManager.getVsqFile();
            Object[]              args   = (Object[])arg;
            List <PatchWorkQueue> queue  = (List <PatchWorkQueue>)args[0];
            List <int>            tracks = (List <int>)args[1];
            int    finished = queue.Count;
            string temppath = AppManager.getTempWaveDir();
            for (int k = 0; k < tracks.Count; k++)
            {
                int        track      = tracks[k];
                string     wavePath   = Path.Combine(temppath, track + ".wav");
                List <int> queueIndex = new List <int>();

                for (int i = 0; i < queue.Count; i++)
                {
                    if (queue[i].track == track)
                    {
                        queueIndex.Add(i);
                    }
                }

                if (queueIndex.Count <= 0)
                {
                    // 第trackトラックに対してパッチワークを行う必要無し
                    continue;
                }

#if DEBUG
                sout.println("AppManager#pathWorkToFreeze; wavePath=" + wavePath + "; queue.get( queueIndex.get( 0 ) ).file=" + queue[queueIndex[0]].file);
                sout.println("AppManager#pathWorkToFreeze; queueIndex.size()=" + queueIndex.Count);
#endif
                if (queueIndex.Count == 1 && wavePath.Equals(queue[queueIndex[0]].file))
                {
                    // 第trackトラック全体の合成を指示するキューだった場合.
                    // このとき,パッチワークを行う必要なし.
                    AppManager.mLastRenderedStatus[track - 1] =
                        new RenderedStatus((VsqTrack)vsq.Track[track].clone(), vsq.TempoTable, (SequenceConfig)vsq.config.clone());
                    AppManager.serializeRenderingStatus(temppath, track);
                    AppManager.invokeWaveViewReloadRequiredEvent(track, wavePath, 1, -1);
                    continue;
                }

                WaveWriter writer = null;
                try {
                    int  sampleRate  = vsq.config.SamplingRate;
                    long totalLength = (long)((vsq.getSecFromClock(vsq.TotalClocks) + 1.0) * sampleRate);
                    writer = new WaveWriter(wavePath, vsq.config.WaveFileOutputChannel, 16, sampleRate);
                    int      BUFLEN = 1024;
                    double[] bufl   = new double[BUFLEN];
                    double[] bufr   = new double[BUFLEN];
                    double   total  = 0.0;
                    for (int m = 0; m < queueIndex.Count; m++)
                    {
                        int i = queueIndex[m];
                        if (finished <= i)
                        {
                            break;
                        }

                        // パッチワークの開始秒時
                        double secStart    = vsq.getSecFromClock(queue[i].clockStart);
                        long   sampleStart = (long)(secStart * sampleRate);

                        // パッチワークの終了秒時
                        int clockEnd = queue[i].clockEnd;
                        if (clockEnd == int.MaxValue)
                        {
                            clockEnd = vsq.TotalClocks + 240;
                        }
                        double secEnd    = vsq.getSecFromClock(clockEnd);
                        long   sampleEnd = (long)(secEnd * sampleRate);

                        WaveReader wr = null;
                        try {
                            wr = new WaveReader(queue[i].file);
                            long remain2 = sampleEnd - sampleStart;
                            long proc    = 0;
                            while (remain2 > 0)
                            {
                                int delta = remain2 > BUFLEN ? BUFLEN : (int)remain2;
                                wr.read(proc, delta, bufl, bufr);
                                writer.replace(sampleStart + proc, delta, bufl, bufr);
                                proc    += delta;
                                remain2 -= delta;
                                total   += delta;
                                state.reportProgress(total);
                            }
                        } catch (Exception ex) {
                            Logger.write(typeof(AppManager) + ".patchWorkToFreeze; ex=" + ex + "\n");
                            serr.println("AppManager#patchWorkToFreeze; ex=" + ex);
                        } finally {
                            if (wr != null)
                            {
                                try {
                                    wr.close();
                                } catch (Exception ex2) {
                                    Logger.write(typeof(AppManager) + ".patchWorkToFreeze; ex=" + ex2 + "\n");
                                    serr.println("AppManager#patchWorkToFreeze; ex2=" + ex2);
                                }
                            }
                        }

                        try {
                            PortUtil.deleteFile(queue[i].file);
                        } catch (Exception ex) {
                            Logger.write(typeof(AppManager) + ".patchWorkToFreeze; ex=" + ex + "\n");
                            serr.println("AppManager#patchWorkToFreeze; ex=" + ex);
                        }
                    }

                    VsqTrack vsq_track = vsq.Track[track];
                    if (queueIndex[queueIndex.Count - 1] <= finished)
                    {
                        // 途中で終了せず,このトラックの全てのパッチワークが完了した.
                        AppManager.mLastRenderedStatus[track - 1] =
                            new RenderedStatus((VsqTrack)vsq_track.clone(), vsq.TempoTable, (SequenceConfig)vsq.config.clone());
                        AppManager.serializeRenderingStatus(temppath, track);
                        AppManager.setRenderRequired(track, false);
                    }
                    else
                    {
                        // パッチワークの作成途中で,キャンセルされた
                        // キャンセルされたやつ以降の範囲に、プログラムチェンジ17の歌手変更イベントを挿入する。→AppManager#detectTrackDifferenceに必ず検出してもらえる。
                        VsqTrack copied = (VsqTrack)vsq_track.clone();
                        VsqEvent dumy   = new VsqEvent();
                        dumy.ID.type               = VsqIDType.Singer;
                        dumy.ID.IconHandle         = new IconHandle();
                        dumy.ID.IconHandle.Program = 17;
                        for (int m = 0; m < queueIndex.Count; m++)
                        {
                            int i = queueIndex[m];
                            if (i < finished)
                            {
                                continue;
                            }
                            int      start       = queue[i].clockStart;
                            int      end         = queue[i].clockEnd;
                            VsqEvent singerAtEnd = vsq_track.getSingerEventAt(end);

                            // startの位置に歌手変更が既に指定されていないかどうかを検査
                            int foundStart = -1;
                            int foundEnd   = -1;
                            for (Iterator <int> itr = copied.indexIterator(IndexIteratorKind.SINGER); itr.hasNext();)
                            {
                                int      j  = itr.next();
                                VsqEvent ve = copied.getEvent(j);
                                if (ve.Clock == start)
                                {
                                    foundStart = j;
                                }
                                if (ve.Clock == end)
                                {
                                    foundEnd = j;
                                }
                                if (end < ve.Clock)
                                {
                                    break;
                                }
                            }

                            VsqEvent dumyStart = (VsqEvent)dumy.clone();
                            dumyStart.Clock = start;
                            if (foundStart >= 0)
                            {
                                copied.setEvent(foundStart, dumyStart);
                            }
                            else
                            {
                                copied.addEvent(dumyStart);
                            }

                            if (end != int.MaxValue)
                            {
                                VsqEvent dumyEnd = (VsqEvent)singerAtEnd.clone();
                                dumyEnd.Clock = end;
                                if (foundEnd >= 0)
                                {
                                    copied.setEvent(foundEnd, dumyEnd);
                                }
                                else
                                {
                                    copied.addEvent(dumyEnd);
                                }
                            }

                            copied.sortEvent();
                        }

                        AppManager.mLastRenderedStatus[track - 1] = new RenderedStatus(copied, vsq.TempoTable, (SequenceConfig)vsq.config.clone());
                        AppManager.serializeRenderingStatus(temppath, track);
                    }

                    state.reportComplete();
                } catch (Exception ex) {
                    Logger.write(typeof(AppManager) + ".patchWorkToFreeze; ex=" + ex + "\n");
                    serr.println("AppManager#patchWorkToFreeze; ex=" + ex);
                } finally {
                    if (writer != null)
                    {
                        try {
                            writer.close();
                        } catch (Exception ex2) {
                            Logger.write(typeof(AppManager) + ".patchWorkToFreeze; ex=" + ex2 + "\n");
                            serr.println("AppManager#patchWorkToFreeze; ex2=" + ex2);
                        }
                    }
                }

                // 波形表示用のWaveDrawContextの内容を更新する。

                /*for ( int j = 0; j < queueIndex.size(); j++ ) {
                 *  int i = queueIndex.get( j );
                 *  if ( i >= finished ) {
                 *      continue;
                 *  }
                 *  double secStart = mVsq.getSecFromClock( queue.get( i ).clockStart );
                 *  int clockEnd = queue.get( i ).clockEnd;
                 *  if ( clockEnd == int.MaxValue ) {
                 *      clockEnd = mVsq.TotalClocks + 240;
                 *  }
                 *  double secEnd = mVsq.getSecFromClock( clockEnd );
                 *
                 *  invokeWaveViewReloadRequiredEvent( tracks.get( k ), wavePath, secStart, secEnd );
                 * }*/
                AppManager.invokeWaveViewReloadRequiredEvent(track, wavePath, 1, -1);
            }
#if DEBUG
            sout.println("SynthesizeWorker#patchWork; done");
#endif
            state.reportComplete();
        }
        public void processQueue(WorkerState state, Object arg)
        {
#if DEBUG
            sout.println("SynthesizeWorker#processQueue");
#endif
            PatchWorkQueue q                = (PatchWorkQueue)arg;
            VsqFileEx      vsq              = q.vsq;
            int            channel          = vsq.config.WaveFileOutputChannel == 1 ? 1 : 2;
            double         amp_master       = VocaloSysUtil.getAmplifyCoeffFromFeder(vsq.Mixer.MasterFeder);
            double         pan_left_master  = VocaloSysUtil.getAmplifyCoeffFromPanLeft(vsq.Mixer.MasterPanpot);
            double         pan_right_master = VocaloSysUtil.getAmplifyCoeffFromPanRight(vsq.Mixer.MasterPanpot);
            int            numTrack         = vsq.Track.Count;
            string         tmppath          = AppManager.getTempWaveDir();
            int            track            = q.track;

            VsqTrack vsq_track = vsq.Track[track];
            int      count     = vsq_track.getEventCount();
            if (count <= 0)
            {
                return;// false;
            }
            double amp_track       = VocaloSysUtil.getAmplifyCoeffFromFeder(vsq.Mixer.Slave[track - 1].Feder);
            double pan_left_track  = VocaloSysUtil.getAmplifyCoeffFromPanLeft(vsq.Mixer.Slave[track - 1].Panpot);
            double pan_right_track = VocaloSysUtil.getAmplifyCoeffFromPanRight(vsq.Mixer.Slave[track - 1].Panpot);
            double amp_left        = amp_track * pan_left_track;
            double amp_right       = amp_track * pan_right_track;
            int    total_clocks    = vsq.TotalClocks;
            double total_sec       = vsq.getSecFromClock(total_clocks);

            RendererKind kind = VsqFileEx.getTrackRendererKind(vsq_track);
            mGenerator = VSTiDllManager.getWaveGenerator(kind);
            Amplifier amp = new Amplifier();
            amp.setRoot(mGenerator);
            if (q.renderAll)
            {
                amp.setAmplify(amp_left, amp_right);
            }
            mGenerator.setReceiver(amp);
            mGenerator.setGlobalConfig(AppManager.editorConfig);
            mGenerator.setMainWindow(mMainWindow);

            Mixer mixer = new Mixer();
            mixer.setRoot(mGenerator);
            mixer.setGlobalConfig(AppManager.editorConfig);
            amp.setReceiver(mixer);

            if (q.renderAll && vsq.config.WaveFileOutputFromMasterTrack)
            {
                // トラック全体を合成するモードで,かつ,他トラックを合成して出力するよう指示された場合
                if (numTrack > 2)
                {
                    for (int i = 1; i < numTrack; i++)
                    {
                        if (i == track)
                        {
                            continue;
                        }
                        string file = Path.Combine(tmppath, i + ".wav");
                        if (!File.Exists(file))
                        {
                            // mixするべきファイルが揃っていないのでbailout
                            return;// true;
                        }
                        WaveReader r = null;
                        try {
                            r = new WaveReader(file);
                        } catch (Exception ex) {
                            Logger.write(typeof(SynthesizeWorker) + ".processQueue; ex=" + ex + "\n");
                            r = null;
                        }
                        if (r == null)
                        {
                            return;// true;
                        }
                        double end_sec = vsq.getSecFromClock(q.clockStart);
                        r.setOffsetSeconds(end_sec);
                        Amplifier amp_i_unit = new Amplifier();
                        amp_i_unit.setRoot(mGenerator);
                        double amp_i       = VocaloSysUtil.getAmplifyCoeffFromFeder(vsq.Mixer.Slave[i - 1].Feder);
                        double pan_left_i  = VocaloSysUtil.getAmplifyCoeffFromPanLeft(vsq.Mixer.Slave[i - 1].Panpot);
                        double pan_right_i = VocaloSysUtil.getAmplifyCoeffFromPanRight(vsq.Mixer.Slave[i - 1].Panpot);
                        double amp_left_i  = amp_i * pan_left_i;
                        double amp_right_i = amp_i * pan_right_i;
#if DEBUG
                        sout.println("FormSynthesize#bgWork_DoWork; #" + i + "; amp_left_i=" + amp_left_i + "; amp_right_i=" + amp_right_i);
#endif
                        amp_i_unit.setAmplify(amp_left_i, amp_right_i);
                        FileWaveSender wave_sender = new FileWaveSender(r);
                        wave_sender.setRoot(mGenerator);
                        wave_sender.setGlobalConfig(AppManager.editorConfig);

                        amp_i_unit.setSender(wave_sender);
                        mixer.addSender(amp_i_unit);
                    }
                }
            }

            PortUtil.deleteFile(q.file);
            int sample_rate = vsq.config.SamplingRate;
#if DEBUG
            sout.println("FormSynthesize#bgWork_DoWork; q.file=" + q.file);
#endif
            FileWaveReceiver wave_receiver = new FileWaveReceiver(q.file, channel, 16, sample_rate);
            wave_receiver.setRoot(mGenerator);
            wave_receiver.setGlobalConfig(AppManager.editorConfig);
            Amplifier amp_unit_master = new Amplifier();
            amp_unit_master.setRoot(mGenerator);
            if (q.renderAll)
            {
                double l = amp_master * pan_left_master;
                double r = amp_master * pan_right_master;
                amp_unit_master.setAmplify(l, r);
            }
            mixer.setReceiver(amp_unit_master);
            amp_unit_master.setReceiver(wave_receiver);

            int end = q.clockEnd;
            if (end == int.MaxValue)
            {
                end = vsq.TotalClocks + 240;
            }
            mGenerator.init(vsq, track, q.clockStart, end, sample_rate);

            double sec_start = vsq.getSecFromClock(q.clockStart);
            double sec_end   = vsq.getSecFromClock(end);
            long   samples   = (long)((sec_end - sec_start) * sample_rate);
            mGenerator.begin(samples, state);

            return;// false;
        }
Exemple #13
0
        private static void ThreadProc()
        {
            const int TOLERANCE_MILLISEC = 10;

            while (!m_stop_required)
            {
                if (s_queue.size() == 0)
                {
                    Thread.Sleep(100);
                    continue;
                }
                int    clock     = s_queue.get(0).Clock;
                double tick_sec  = m_vsq.getSecFromClock(clock);
                double next_tick = m_started + ((tick_sec - m_started_sec) / m_speed);
                double now       = PortUtil.getCurrentTime();
                double time_span = next_tick - now;
                if (time_span <= 0)
                {
                    Vector <MidiQueue> add = new Vector <MidiQueue>();
                    while (s_queue.size() > 0 && s_queue.get(0).Clock == clock)
                    {
                        if (s_queue.get(0).Done != null)
                        {
                            add.addAll(s_queue.get(0).Done(s_queue.get(0)));
                        }
                        MidiQueue item = s_queue.get(0);
                        if (item.Track == 0 || s_metronome_device == s_general_device)
                        {
                            s_device0.Play(item.Channel, item.Program, item.Note, item.Velocity);
                        }
                        else
                        {
                            s_device1.Play(item.Channel, item.Program, item.Note, item.Velocity);
                        }
                        s_queue.removeElementAt(0);
                    }
                    s_queue.addAll(add);
                    Collections.sort(s_queue);
                    continue;
                }
                int wait_millisec = (int)((next_tick - PortUtil.getCurrentTime()) * 1000.0) - PreUtterance;
                int thiswait      = (wait_millisec > TOLERANCE_MILLISEC * 2) ? TOLERANCE_MILLISEC * 2 : wait_millisec;
#if DEBUG
                AppManager.debugWriteLine("MidiPlayer#ThreadProc; wait_millisec=" + wait_millisec);
#endif
                while (thiswait > TOLERANCE_MILLISEC)
                {
                    Thread.Sleep(thiswait);
                    wait_millisec = (int)((next_tick - PortUtil.getCurrentTime()) * 1000.0) - PreUtterance;
                    if (wait_millisec < TOLERANCE_MILLISEC || m_stop_required)
                    {
                        break;
                    }
                    thiswait = wait_millisec;
                }
                if (m_stop_required)
                {
                    break;
                }
                if (m_temp_exit)
                {
                    m_temp_exit = false;
                    Vector <MidiQueue> add = new Vector <MidiQueue>();
                    while (s_queue.size() > 0 && s_queue.get(0).Clock == clock)
                    {
                        if (s_queue.get(0).Done != null)
                        {
                            add.addAll(s_queue.get(0).Done(s_queue.get(0)));
                        }
                        s_queue.removeElementAt(0);
                    }
                    s_queue.addAll(add);
                    Collections.sort(s_queue);
                    continue;
                }
                Vector <MidiQueue> adding = new Vector <MidiQueue>();
                while (s_queue.size() > 0 && s_queue.get(0).Clock == clock)
                {
                    if (s_queue.get(0).Track == 0 || s_metronome_device == s_general_device)
                    {
                        if (s_queue.get(0).Track != 0 || (s_queue.get(0).Track == 0 && !m_stop_metronome_required))
                        {
                            s_device0.Play(s_queue.get(0).Channel, s_queue.get(0).Program, s_queue.get(0).Note, s_queue.get(0).Velocity);
                        }
                    }
                    else
                    {
                        s_device1.Play(s_queue.get(0).Channel, s_queue.get(0).Program, s_queue.get(0).Note, s_queue.get(0).Velocity);
                    }
                    if (s_queue.get(0).Done != null)
                    {
                        if (s_queue.get(0).Track != 0 || (s_queue.get(0).Track == 0 && !m_stop_metronome_required))
                        {
                            adding.addAll(s_queue.get(0).Done(s_queue.get(0)));
                        }
                    }
                    s_queue.removeElementAt(0);
                }
                s_queue.addAll(adding);
                Collections.sort(s_queue);
            }
        }
        /// <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);
        }