private static void appendParameterEvents(EventQueueSequence list, VsqBPList cle, int parameter_index, int clock_start, int clock_end)
        {
            int   max   = cle.getMaximum();
            int   min   = cle.getMinimum();
            float order = 1.0f / (float)(max - min);

            if (cle != null)
            {
                int keycount = cle.size();
                for (int i = 0; i < keycount; i++)
                {
                    int clock = cle.getKeyClock(i);
                    if (clock_start <= clock && clock <= clock_end)
                    {
                        int            value = cle.getElementA(i);
                        MidiEventQueue queue = list.get(clock);
                        ParameterEvent pe    = new ParameterEvent();
                        pe.index = parameter_index;
                        pe.value = (value - min) * order;
                        queue.param.add(pe);
                    }
                    else if (clock_end < clock)
                    {
                        break;
                    }
                }
            }
        }
Ejemplo n.º 2
0
    public static bool edit(VsqFile vsq)
    {
        ResoXAmp form = new ResoXAmp();

        if (form.ShowDialog() != DialogResult.OK)
        {
            return(false);
        }
        VsqTrack  track    = vsq.Track[AppManager.Selected];
        VsqBPList source   = track.getCurve(CurveType.reso1amp.getName());
        VsqBPList reso2amp = (VsqBPList)track.getCurve(CurveType.reso2amp.getName()).clone();
        VsqBPList reso3amp = (VsqBPList)track.getCurve(CurveType.reso3amp.getName()).clone();
        VsqBPList reso4amp = (VsqBPList)track.getCurve(CurveType.reso4amp.getName()).clone();

        Console.WriteLine("AmplifyCoeffReso2=" + AmplifyCoeffReso2);
        Console.WriteLine("AmplifyCoeffReso3=" + AmplifyCoeffReso3);
        Console.WriteLine("AmplifyCoeffReso4=" + AmplifyCoeffReso4);
        amplify(source, reso2amp, AmplifyCoeffReso2);
        amplify(source, reso3amp, AmplifyCoeffReso3);
        amplify(source, reso4amp, AmplifyCoeffReso4);
        track.setCurve(CurveType.reso2amp.getName(), reso2amp);
        track.setCurve(CurveType.reso3amp.getName(), reso3amp);
        track.setCurve(CurveType.reso4amp.getName(), reso4amp);
        Console.WriteLine("reso2amp.getCount()=" + reso2amp.size());
        Console.WriteLine("reso3amp.getCount()=" + reso3amp.size());
        Console.WriteLine("reso4amp.getCount()=" + reso4amp.size());
        MessageBox.Show("done");
        return(true);
    }
        public void testReflectVibratoPitch()
        {
            var tempoTable = new TempoVector();
            var pitchBend = new VsqBPList( CurveType.PIT.getName(), CurveType.PIT.getDefault(), CurveType.PIT.getMinimum(), CurveType.PIT.getMaximum() );
            var pitchBendSensitivity = new VsqBPList( CurveType.PIT.getName(), CurveType.PIT.getDefault(), CurveType.PIT.getMinimum(), CurveType.PIT.getMaximum() );

            pitchBend.add( 0, 8191 );
            pitchBendSensitivity.add( 0, 2 );

            var generator = new AquesTone2WaveGeneratorStub();
            var item = new VsqEvent( 0, new VsqID() );
            item.ID.type = VsqIDType.Anote;
            item.ID.VibratoHandle = new VibratoHandle();
            item.ID.VibratoHandle.StartRate = 0x40;
            item.ID.VibratoHandle.RateBP.clear();
            item.ID.VibratoHandle.StartDepth = 0x40;
            item.ID.VibratoHandle.DepthBP.clear();
            item.ID.setLength( 480 );
            item.ID.VibratoDelay = 430;
            item.ID.VibratoHandle.setLength( 50 );
            generator.reflectVibratoPitch( item, pitchBend, pitchBendSensitivity, tempoTable );

            {
                var expectedPit = new Dictionary<int, int> {
                    { 0, 8191 },
                    { 430, 5461 }, { 431, 5467 }, { 432, 5484 }, { 433, 5514 }, { 434, 5555 },
                    { 435, 5608 }, { 436, 5672 }, { 437, 5748 }, { 438, 5835 }, { 439, 5932 },
                    { 440, 6041 }, { 441, 6096 }, { 442, 6151 }, { 443, 6205 }, { 444, 6257 },
                    { 445, 6309 }, { 446, 6360 }, { 447, 6410 }, { 448, 6459 }, { 449, 6507 },
                    { 450, 6553 }, { 451, 6598 }, { 452, 6642 }, { 453, 6684 }, { 454, 6725 },
                    { 455, 6764 }, { 456, 6802 }, { 457, 6838 }, { 458, 6873 }, { 459, 6906 },
                    { 460, 6937 }, { 461, 6967 }, { 462, 6994 }, { 463, 7020 }, { 464, 7044 },
                    { 465, 7066 }, { 466, 7087 }, { 467, 7105 }, { 468, 7121 }, { 469, 7136 },
                    { 470, 7148 }, { 471, 6989 }, { 472, 6826 }, { 473, 6660 }, { 474, 6491 },
                    { 475, 6320 }, { 476, 6149 }, { 477, 5976 }, { 478, 5804 }, { 479, 5632 },
                    { 480, 8191 }
                };
                Assert.AreEqual( expectedPit.Count, pitchBend.size() );
                int i = 0;
                foreach ( var pitInfo in expectedPit ) {
                    Assert.AreEqual( pitInfo.Key, pitchBend.getKeyClock( i ) );
                    Assert.AreEqual( pitInfo.Value, pitchBend.getElementA( i ) );
                    ++i;
                }
            }

            {
                var expectedPbs = new Dictionary<int, int> {
                    { 0, 2 }, { 430, 3 }, { 480, 2 }
                };
                Assert.AreEqual( expectedPbs.Count, pitchBendSensitivity.size() );
                int i = 0;
                foreach ( var pbsInfo in expectedPbs ) {
                    Assert.AreEqual( pbsInfo.Key, pitchBendSensitivity.getKeyClock( i ) );
                    Assert.AreEqual( pbsInfo.Value, pitchBendSensitivity.getElementA( i ) );
                    ++i;
                }
            }
        }
Ejemplo n.º 4
0
 private static void amplify( VsqBPList source, VsqBPList target, double amplify ) {
     target.clear();
     int count = source.size();
     int min = target.getMinimum();
     int max = target.getMaximum();
     for ( int i = 0; i < count; i++ ) {
         int clock = source.getKeyClock( i );
         int value = (int)(source.getElement( i ) * amplify);
         if ( value < min ) {
             value = min;
         }
         if ( max < value ) {
             value = max;
         }
         target.add( clock, value );
     }
 }
Ejemplo n.º 5
0
    private static void amplify(VsqBPList source, VsqBPList target, double amplify)
    {
        target.clear();
        int count = source.size();
        int min   = target.getMinimum();
        int max   = target.getMaximum();

        for (int i = 0; i < count; i++)
        {
            int clock = source.getKeyClock(i);
            int value = (int)(source.getElement(i) * amplify);
            if (value < min)
            {
                value = min;
            }
            if (max < value)
            {
                value = max;
            }
            target.add(clock, value);
        }
    }
Ejemplo n.º 6
0
    public static ScriptReturnStatus Edit( VsqFileEx vsq )
    {
        // 選択状態のアイテムがなければ戻る
        if ( AppManager.itemSelection.getEventCount() <= 0 ) {
            return ScriptReturnStatus.NOT_EDITED;
        }

        // 現在のトラック
        int selected = AppManager.getSelected();
        VsqTrack vsq_track = vsq.Track.get( selected );
        vsq_track.sortEvent();

        // プラグイン情報の定義ファイル(plugin.txt)があるかどうかチェック
        string pluginTxtPath = s_plugin_txt_path;
        if ( pluginTxtPath == "" ) {
            AppManager.showMessageBox( "pluginTxtPath=" + pluginTxtPath );
            return ScriptReturnStatus.ERROR;
        }
        if ( !System.IO.File.Exists( pluginTxtPath ) ) {
            AppManager.showMessageBox( "'" + pluginTxtPath + "' does not exists" );
            return ScriptReturnStatus.ERROR;
        }

        // plugin.txtがあれば,プラグインの実行ファイルのパスを取得する
        System.Text.Encoding shift_jis = System.Text.Encoding.GetEncoding( "Shift_JIS" );
        string name = "";
        string exe_path = "";
        using ( StreamReader sr = new StreamReader( pluginTxtPath, shift_jis ) ) {
            string line = "";
            while ( (line = sr.ReadLine()) != null ) {
                string[] spl = line.Split( new char[] { '=' }, StringSplitOptions.RemoveEmptyEntries );
                if ( line.StartsWith( "name=" ) ) {
                    name = spl[1];
                } else if ( line.StartsWith( "execute=" ) ) {
                    exe_path = Path.Combine( Path.GetDirectoryName( pluginTxtPath ), spl[1] );
                }
            }
        }
        if ( exe_path == "" ) {
            return ScriptReturnStatus.ERROR;
        }
        if ( !System.IO.File.Exists( exe_path ) ) {
            AppManager.showMessageBox( "'" + exe_path + "' does not exists" );
            return ScriptReturnStatus.ERROR;
        }

        // 選択状態のアイテムの最初と最後がどこか調べる
        // clock_start, clock_endは,最終的にはPREV, NEXTを含んだ範囲を表すことになる
        // sel_start, sel_endはPREV, NEXTを含まない選択範囲を表す
        int id_start = -1;
        int clock_start = int.MaxValue;
        int id_end = -1;
        int clock_end = int.MinValue;
        int sel_start = 0;
        int sel_end = 0;
        for ( Iterator<SelectedEventEntry> itr = AppManager.itemSelection.getEventIterator(); itr.hasNext(); ) {
            SelectedEventEntry item = itr.next();
            if ( item.original.ID.type != VsqIDType.Anote ) {
                continue;
            }
            int clock = item.original.Clock;
            if ( clock < clock_start ) {
                id_start = item.original.InternalID;
                clock_start = clock;
                sel_start = clock;
            }
            clock += item.original.ID.getLength();
            if ( clock_end < clock ) {
                id_end = item.original.InternalID;
                clock_end = clock;
                sel_end = clock;
            }
        }

        // 選択範囲の前後の音符を探す
        VsqEvent ve_prev = null;
        VsqEvent ve_next = null;
        VsqEvent l = null;
        for ( Iterator<VsqEvent> itr = vsq_track.getNoteEventIterator(); itr.hasNext(); ) {
            VsqEvent item = itr.next();
            if ( item.InternalID == id_start ) {
                if ( l != null ) {
                    ve_prev = l;
                }
            }
            if ( l != null ) {
                if ( l.InternalID == id_end ) {
                    ve_next = item;
                }
            }
            l = item;
            if ( ve_prev != null && ve_next != null ) {
                break;
            }
        }
        int next_rest_clock = -1;
        bool prev_is_rest = false;
        if ( ve_prev != null ) {
            // 直前の音符がある場合
            if ( ve_prev.Clock + ve_prev.ID.getLength() == clock_start ) {
                // 接続している
                clock_start = ve_prev.Clock;
            } else {
                // 接続していない
                int new_clock_start = ve_prev.Clock + ve_prev.ID.getLength();
                clock_start = new_clock_start;
            }
        } else {
            // 無い場合
            if ( vsq.getPreMeasureClocks() < clock_start ) {
                prev_is_rest = true;
            }
            int new_clock_start = vsq.getPreMeasureClocks();
            clock_start = new_clock_start;
        }
        if ( ve_next != null ) {
            // 直後の音符がある場合
            if ( ve_next.Clock == clock_end ) {
                // 接続している
                clock_end = ve_next.Clock + ve_next.ID.getLength();
            } else {
                // 接続していない
                next_rest_clock = clock_end;
                clock_end = ve_next.Clock;
            }
        }

        // 作業用のVSQに,選択範囲のアイテムを格納
        VsqFileEx v = (VsqFileEx)vsq.clone();// new VsqFile( "Miku", 1, 4, 4, 500000 );
        // 選択トラックだけ残して他を削る
        for ( int i = 1; i < selected; i++ ) {
            v.Track.removeElementAt( 1 );
        }
        for ( int i = selected + 1; i < v.Track.size(); i++ ) {
            v.Track.removeElementAt( selected + 1 );
        }
        // 選択トラックの音符を全消去する
        VsqTrack v_track = v.Track.get( 1 );
        v_track.MetaText.getEventList().clear();
        for ( Iterator<VsqEvent> itr = vsq_track.getNoteEventIterator(); itr.hasNext(); ) {
            VsqEvent item = itr.next();
            if ( clock_start <= item.Clock && item.Clock + item.ID.getLength() <= clock_end ) {
                v_track.addEvent( (VsqEvent)item.clone(), item.InternalID );
            }
        }
        // 最後のRを手動で追加.これは自動化できない
        if ( next_rest_clock != -1 ) {
            VsqEvent item = (VsqEvent)ve_next.clone();
            item.ID.LyricHandle.L0.Phrase = "R";
            item.Clock = next_rest_clock;
            item.ID.setLength( clock_end - next_rest_clock );
            v_track.addEvent( item );
        }
        // 0~選択範囲の開始位置までを削除する
        v.removePart( 0, clock_start );

        // vsq -> ustに変換
        // キーがustのIndex, 値がInternalID
        TreeMap<int, int> map = new TreeMap<int, int>();
        UstFile u = new UstFile( v, 1, map );

        u.write( Path.Combine( PortUtil.getApplicationStartupPath(), "u.ust" ) );

        // PREV, NEXTのIndex値を設定する
        if ( ve_prev != null || prev_is_rest ) {
            u.getTrack( 0 ).getEvent( 0 ).Index = UstFile.PREV_INDEX;
        }
        if ( ve_next != null ) {
            u.getTrack( 0 ).getEvent( u.getTrack( 0 ).getEventCount() - 1 ).Index = UstFile.NEXT_INDEX;
        }

        // ustファイルに出力
        UstFileWriteOptions option = new UstFileWriteOptions();
        option.settingCacheDir = false;
        option.settingOutFile = false;
        option.settingProjectName = false;
        option.settingTempo = true;
        option.settingTool1 = true;
        option.settingTool2 = true;
        option.settingTracks = false;
        option.settingVoiceDir = true;
        option.trackEnd = false;
        string temp = Path.GetTempFileName();
        u.write( temp, option );

        StringBuilder before = new StringBuilder();
        using ( StreamReader sr = new StreamReader( temp, System.Text.Encoding.GetEncoding( "Shift_JIS" ) ) ) {
            string line = "";
            while ( (line = sr.ReadLine()) != null ) {
                before.AppendLine( line );
            }
        }
        String md5_before = PortUtil.getMD5FromString( before.ToString() );
        // プラグインの実行ファイルを起動
        Utau_Plugin_Invoker dialog = new Utau_Plugin_Invoker( exe_path, temp );
        dialog.ShowDialog();
        StringBuilder after = new StringBuilder();
        using ( StreamReader sr = new StreamReader( temp, System.Text.Encoding.GetEncoding( "Shift_JIS" ) ) ) {
            string line = "";
            while ( (line = sr.ReadLine()) != null ) {
                after.AppendLine( line );
            }
        }
        String md5_after = PortUtil.getMD5FromString( after.ToString() );
        if ( md5_before == md5_after ) {
            // 編集されなかったようだ
            return ScriptReturnStatus.NOT_EDITED;
        }

        // プラグインの実行結果をustオブジェクトにロード
        UstFile r = new UstFile( temp );
        if ( r.getTrackCount() < 1 ) {
            return ScriptReturnStatus.ERROR;
        }

        // 変更のなかったものについてはプラグインは記録してこないので,
        // 最初の値を代入するようにする
        UstTrack utrack_src = u.getTrack( 0 );
        UstTrack utrack_dst = r.getTrack( 0 );
        for ( int i = 0; i < utrack_dst.getEventCount(); i++ ) {
            UstEvent ue_dst = utrack_dst.getEvent( i );
            int index = ue_dst.Index;
            UstEvent ue_src = utrack_src.findEventFromIndex( index );
            if ( ue_src == null ) {
                continue;
            }
            if ( !ue_dst.isEnvelopeSpecified() && ue_src.isEnvelopeSpecified() ) {
                ue_dst.setEnvelope( ue_src.getEnvelope() );
            }
            if ( !ue_dst.isIntensitySpecified() && ue_src.isIntensitySpecified() ) {
                ue_dst.setIntensity( ue_src.getIntensity() );
            }
            if ( !ue_dst.isLengthSpecified() && ue_src.isLengthSpecified() ) {
                ue_dst.setLength( ue_src.getLength() );
            }
            if ( !ue_dst.isLyricSpecified() && ue_src.isLyricSpecified() ) {
                ue_dst.setLyric( ue_src.getLyric() );
            }
            if ( !ue_dst.isModurationSpecified() && ue_src.isModurationSpecified() ) {
                ue_dst.setModuration( ue_src.getModuration() );
            }
            if ( !ue_dst.isNoteSpecified() && ue_src.isNoteSpecified() ) {
                ue_dst.setNote( ue_src.getNote() );
            }
            if ( !ue_dst.isPBTypeSpecified() && ue_src.isPBTypeSpecified() ) {
                ue_dst.setPBType( ue_src.getPBType() );
            }
            if ( !ue_dst.isPitchesSpecified() && ue_src.isPitchesSpecified() ) {
                ue_dst.setPitches( ue_src.getPitches() );
            }
            if ( !ue_dst.isPortamentoSpecified() && ue_src.isPortamentoSpecified() ) {
                ue_dst.setPortamento( ue_src.getPortamento() );
            }
            if ( !ue_dst.isPreUtteranceSpecified() && ue_src.isPreUtteranceSpecified() ) {
                ue_dst.setPreUtterance( ue_src.getPreUtterance() );
            }
            if ( !ue_dst.isStartPointSpecified() && ue_src.isStartPointSpecified() ) {
                ue_dst.setStartPoint( ue_src.getStartPoint() );
            }
            if ( !ue_dst.isTempoSpecified() && ue_src.isTempoSpecified() ) {
                ue_dst.setTempo( ue_src.getTempo() );
            }
            if ( !ue_dst.isVibratoSpecified() && ue_src.isVibratoSpecified() ) {
                ue_dst.setVibrato( ue_src.getVibrato() );
            }
            if ( !ue_dst.isVoiceOverlapSpecified() && ue_src.isVoiceOverlapSpecified() ) {
                ue_dst.setVoiceOverlap( ue_src.getVoiceOverlap() );
            }
        }

        // PREVとNEXT含めて,clock_startからclock_endまでプラグインに渡したけれど,
        // それが伸びて帰ってきたか縮んで帰ってきたか.
        int ret_length = 0;
        UstTrack r_track = r.getTrack( 0 );
        int size = r_track.getEventCount();
        for ( int i = 0; i < size; i++ ) {
            UstEvent ue = r_track.getEvent( i );
            // 戻りのustには,変更があったものしか記録されていない
            int ue_length = ue.getLength();
            if ( !ue.isLengthSpecified() && map.ContainsKey( ue.Index ) ) {
                int internal_id = map[ue.Index];
                VsqEvent found_item = vsq_track.findEventFromID( internal_id );
                if ( found_item != null ) {
                    ue_length = found_item.ID.getLength();
                }
            }
            // PREV, ENDの場合は長さに加えない
            if ( ue.Index != UstFile.NEXT_INDEX &&
                 ue.Index != UstFile.PREV_INDEX ) {
                ret_length += ue_length;
            }
        }

        // 伸び縮みがあった場合
        // 伸ばしたり縮めたりするよ
        int delta = ret_length - (sel_end - sel_start);
        if ( delta > 0 ) {
            // のびた
            vsq.insertBlank( selected, sel_end, delta );
        } else if ( delta < 0 ) {
            // 縮んだ
            vsq.removePart( selected, sel_end + delta, sel_end );
        }

        // r_trackの内容をvsq_trackに転写
        size = r_track.getEventCount();
        int c = clock_start;
        for ( int i = 0; i < size; i++ ) {
            UstEvent ue = r_track.getEvent( i );
            if ( ue.Index == UstFile.NEXT_INDEX || ue.Index == UstFile.PREV_INDEX ) {
                // PREVとNEXTは単に無視する
                continue;
            }
            int ue_length = ue.getLength();
            if ( map.containsKey( ue.Index ) ) {
                // 既存の音符の編集
                VsqEvent target = vsq_track.findEventFromID( map[ue.Index] );
                if ( target == null ) {
                    // そんなばかな・・・
                    continue;
                }
                if ( !ue.isLengthSpecified() ) {
                    ue_length = target.ID.getLength();
                }
                if ( target.UstEvent == null ) {
                    target.UstEvent = (UstEvent)ue.clone();
                }
                // utau固有のパラメータを転写
                // pitchは後でやるので無視していい
                // テンポもあとでやるので無視していい
                if ( ue.isEnvelopeSpecified() ) {
                    target.UstEvent.setEnvelope( ue.getEnvelope() );
                }
                if ( ue.isModurationSpecified() ) {
                    target.UstEvent.setModuration( ue.getModuration() );
                }
                if ( ue.isPBTypeSpecified() ) {
                    target.UstEvent.setPBType( ue.getPBType() );
                }
                if ( ue.isPortamentoSpecified() ) {
                    target.UstEvent.setPortamento( ue.getPortamento() );
                }
                if ( ue.isPreUtteranceSpecified() ) {
                    target.UstEvent.setPreUtterance( ue.getPreUtterance() );
                }
                if ( ue.isStartPointSpecified() ) {
                    target.UstEvent.setStartPoint( ue.getStartPoint() );
                }
                if ( ue.isVibratoSpecified() ) {
                    target.UstEvent.setVibrato( ue.getVibrato() );
                }
                if ( ue.isVoiceOverlapSpecified() ) {
                    target.UstEvent.setVoiceOverlap( ue.getVoiceOverlap() );
                }
                // vocaloid, utauで同じ意味のパラメータを転写
                if ( ue.isIntensitySpecified() ) {
                    target.UstEvent.setIntensity( ue.getIntensity() );
                    target.ID.Dynamics = ue.getIntensity();
                }
                if ( ue.isLengthSpecified() ) {
                    target.UstEvent.setLength( ue.getLength() );
                    target.ID.setLength( ue.getLength() );
                }
                if ( ue.isLyricSpecified() ) {
                    target.UstEvent.setLyric( ue.getLyric() );
                    target.ID.LyricHandle.L0.Phrase = ue.getLyric();
                }
                if ( ue.isNoteSpecified() ) {
                    target.UstEvent.setNote( ue.getNote() );
                    target.ID.Note = ue.getNote();
                }
            } else {
                // マップに入っていないので,新しい音符の追加だと思う
                if ( ue.getLyric() == "R" ) {
                    // 休符.なにもしない
                } else {
                    VsqEvent newe = new VsqEvent();
                    newe.Clock = c;
                    newe.UstEvent = (UstEvent)ue.clone();
                    newe.ID = new VsqID();
                    AppManager.editorConfig.applyDefaultSingerStyle( newe.ID );
                    if ( ue.isIntensitySpecified() ) {
                        newe.ID.Dynamics = ue.getIntensity();
                    }
                    newe.ID.LyricHandle = new LyricHandle( "あ", "a" );
                    if ( ue.isLyricSpecified() ) {
                        newe.ID.LyricHandle.L0.Phrase = ue.getLyric();
                    }
                    newe.ID.Note = ue.getNote();
                    newe.ID.setLength( ue.getLength() );
                    newe.ID.type = VsqIDType.Anote;
                    // internal id はaddEventメソッドで自動で割り振られる
                    vsq_track.addEvent( newe );
                }
            }

            // テンポの追加がないかチェック
            if ( ue.isTempoSpecified() ) {
                insertTempoInto( vsq, c, ue.getTempo() );
            }

            c += ue_length;
        }

        // ピッチを転写
        // pitのデータがほしいので,PREV, NEXTを削除して,VsqFileにコンバートする
        UstFile uf = (UstFile)r.clone();
        // prev, nextを削除
        UstTrack uf_track = uf.getTrack( 0 );
        for ( int i = 0; i < uf_track.getEventCount(); ) {
            UstEvent ue = uf_track.getEvent( i );
            if ( ue.Index == UstFile.NEXT_INDEX ||
                 ue.Index == UstFile.PREV_INDEX ) {
                uf_track.removeEventAt( i );
            } else {
                i++;
            }
        }
        uf.updateTempoInfo();
        // VsqFileにコンバート
        VsqFile uf_vsq = new VsqFile( uf );
        // uf_vsqの最初のトラックの0からret_lengthクロックまでが,
        // vsq_trackのsel_startからsel_start+ret_lengthクロックまでに対応する.
        // まずPBSをコピーする
        CurveType[] type = new CurveType[] { CurveType.PBS, CurveType.PIT };
        foreach ( CurveType ct in type ) {
            // コピー元を取得
            VsqBPList src = uf_vsq.Track[1].getCurve( ct.getName() );
            if ( src != null ) {
                // コピー先を取得
                VsqBPList dst = vsq_track.getCurve( ct.getName() );
                if ( dst == null ) {
                    // コピー先がnullだった場合は作成
                    dst = new VsqBPList( ct.getName(), ct.getDefault(), ct.getMinimum(), ct.getMaximum() );
                    vsq_track.setCurve( ct.getName(), dst );
                }
                // あとで復元するので,最終位置での値を保存しておく
                int value_at_end = dst.getValue( sel_start + ret_length );
                // 復元するかどうか.最終位置にそもそもデータ点があれば復帰の必要がないので.
                bool do_revert = (dst.findIndexFromClock( sel_start + ret_length ) < 0);
                // [sel_start, sel_start + ret_length)の範囲の値を削除しておく
                size = dst.size();
                for ( int i = size - 1; i >= 0; i-- ) {
                    int cl = dst.getKeyClock( i );
                    if ( sel_start <= cl && cl < sel_start + ret_length ) {
                        dst.removeElementAt( i );
                    }
                }
                // コピーを実行
                size = src.size();
                for ( int i = 0; i < size; i++ ) {
                    int cl = src.getKeyClock( i );
                    if ( ret_length <= cl ) {
                        break;
                    }
                    int value = src.getElementA( i );
                    dst.add( cl + sel_start, value );
                }
                // コピー後,最終位置での値が元と異なる場合,元に戻すようにする
                if ( do_revert && dst.getValue( sel_start + ret_length ) != value_at_end ) {
                    dst.add( sel_start + ret_length, value_at_end );
                }
            }
        }

        return ScriptReturnStatus.EDITED;
    }
 public VsqBPListComparisonContext(VsqBPList list1, VsqBPList list2)
 {
     // インデクス0の位置に,デフォルト値を持つダミーがあるように振舞わせる
     this.list1 = list1;
     this.list2 = list2;
 }
 public void reflectVibratoPitch( VsqEvent item, VsqBPList pitchBend, VsqBPList pitchBendSensitivity, TempoVector tempoTable )
 {
     base.reflectNoteEventPitch( item, pitchBend, pitchBendSensitivity, tempoTable );
 }
Ejemplo n.º 9
0
        /// <summary>
        /// 音符に付随するピッチベンドの情報を、PIT・PBS カーブに反映する
        /// </summary>
        /// <param name="item">音符</param>
        /// <param name="pitchBend">PIT カーブ</param>
        /// <param name="pitchBendSensitivity">PBS カーブ</param>
        /// <param name="tempoTable">テンポ情報</param>
        protected void reflectNoteEventPitch( VsqEvent item, VsqBPList pitchBend, VsqBPList pitchBendSensitivity, TempoVector tempoTable )
        {
            if ( item.ID.type != VsqIDType.Anote ) return;
            
            // AquesTone2 では、note on と同 clock にピッチベンドイベントを送らないと音程が反映されないので、必ずピッチイベントが送られるようにする
            pitchBend.add( item.Clock, pitchBend.getValue( item.Clock ) );

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

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

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

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

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

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

            if ( !resetPBS ) {
                return;
            }

            pitchBend.Data = pitBackup.Data;

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

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

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

                const double pow2_13 = 8192;
                double netPitchBendInCent = (pbs * pit / pow2_13) * 100.0 + vibratoPitchBendInCent;
                maxNetPitchBendInCent = Math.Max( maxNetPitchBendInCent, Math.Abs( netPitchBendInCent ) );
                int draftPitchBend = (int)Math.Round((netPitchBendInCent / 100.0) * pow2_13 / requiredPitchbendSensitivity);
                if ( draftPitchBend < pitchBend.Minimum ) draftPitchBend = pitchBend.Minimum;
                if ( pitchBend.Maximum < draftPitchBend ) draftPitchBend = pitchBend.Maximum;
                if ( draftPitchBend != lastPitchBend ) {
                    pitchBend.add( clock, draftPitchBend );
                    lastPitchBend = draftPitchBend;
                }
            }
        }
Ejemplo n.º 10
0
 private static void appendParameterEvents( TreeMap<Integer, MidiEventQueue> list, VsqBPList cle, int parameter_index, int clock_start, int clock_end )
 {
     int max = cle.getMaximum();
     int min = cle.getMinimum();
     float order = 1.0f / (float)(max - min);
     if ( cle != null ) {
         int keycount = cle.size();
         for ( int i = 0; i < keycount; i++ ) {
             int clock = cle.getKeyClock( i );
             if ( clock_start <= clock && clock <= clock_end ) {
                 int value = cle.getElementA( i );
                 MidiEventQueue queue = null;
                 if ( list.containsKey( clock ) ) {
                     queue = list.get( clock );
                 } else {
                     queue = new MidiEventQueue();
                 }
                 if ( queue.param == null ) {
                     queue.param = new Vector<ParameterEvent>();
                 }
                 ParameterEvent pe = new ParameterEvent();
                 pe.index = parameter_index;
                 pe.value = (value - min) * order;
                 queue.param.add( pe );
                 list.put( clock, queue );
             } else if ( clock_end < clock ) {
                 break;
             }
         }
     }
 }
Ejemplo n.º 11
0
        private void applyValue(bool mode_clock)
        {
            if (!m_changed)
            {
                return;
            }
            int value = m_curve.getDefault();

            try {
                value = int.Parse(txtDataPointValue.Text);
            } catch (Exception ex) {
                Logger.write(typeof(FormCurvePointEdit) + ".applyValue; ex=" + ex + "\n");
                return;
            }
            if (value < m_curve.getMinimum())
            {
                value = m_curve.getMinimum();
            }
            else if (m_curve.getMaximum() < value)
            {
                value = m_curve.getMaximum();
            }

            int clock = 0;

            try {
                clock = int.Parse(txtDataPointClock.Text);
            } catch (Exception ex) {
                Logger.write(typeof(FormCurvePointEdit) + ".applyValue; ex=" + ex + "\n");
                return;
            }

            int       selected  = AppManager.getSelected();
            VsqTrack  vsq_track = AppManager.getVsqFile().Track[selected];
            VsqBPList src       = vsq_track.getCurve(m_curve.getName());
            VsqBPList list      = (VsqBPList)src.clone();

            VsqBPPairSearchContext context = list.findElement(m_editing_id);

            list.move(context.clock, clock, value);
            CadenciiCommand run = new CadenciiCommand(VsqCommand.generateCommandTrackCurveReplace(selected,
                                                                                                  m_curve.getName(),
                                                                                                  list));
            EditedZone zone = new EditedZone();

            Utility.compareList(zone, new VsqBPListComparisonContext(list, src));
            List <EditedZoneUnit> zoneUnits = new List <EditedZoneUnit>();

            foreach (var item in zone.iterator())
            {
                zoneUnits.Add(item);
            }
            AppManager.editHistory.register(AppManager.getVsqFile().executeCommand(run));

            txtDataPointClock.Text = clock + "";
            txtDataPointValue.Text = value + "";

            if (mMainWindow != null)
            {
                mMainWindow.setEdited(true);
                mMainWindow.ensureVisible(clock);
                mMainWindow.refreshScreen();
            }

            if (mode_clock)
            {
                txtDataPointClock.SelectAll();
            }
            else
            {
                txtDataPointValue.SelectAll();
            }

            btnUndo.Enabled = AppManager.editHistory.hasUndoHistory();
            btnRedo.Enabled = AppManager.editHistory.hasRedoHistory();
            m_changed       = false;
        }
        public void testReflectVibratoPitch()
        {
            var tempoTable           = new TempoVector();
            var pitchBend            = new VsqBPList(CurveType.PIT.getName(), CurveType.PIT.getDefault(), CurveType.PIT.getMinimum(), CurveType.PIT.getMaximum());
            var pitchBendSensitivity = new VsqBPList(CurveType.PIT.getName(), CurveType.PIT.getDefault(), CurveType.PIT.getMinimum(), CurveType.PIT.getMaximum());

            pitchBend.add(0, 8191);
            pitchBendSensitivity.add(0, 2);

            var generator = new AquesTone2WaveGeneratorStub();
            var item      = new VsqEvent(0, new VsqID());

            item.ID.type                    = VsqIDType.Anote;
            item.ID.VibratoHandle           = new VibratoHandle();
            item.ID.VibratoHandle.StartRate = 0x40;
            item.ID.VibratoHandle.RateBP.clear();
            item.ID.VibratoHandle.StartDepth = 0x40;
            item.ID.VibratoHandle.DepthBP.clear();
            item.ID.setLength(480);
            item.ID.VibratoDelay = 430;
            item.ID.VibratoHandle.setLength(50);
            generator.reflectVibratoPitch(item, pitchBend, pitchBendSensitivity, tempoTable);

            {
                var expectedPit = new Dictionary <int, int> {
                    { 0, 8191 },
                    { 430, 5461 }, { 431, 5467 }, { 432, 5484 }, { 433, 5514 }, { 434, 5555 },
                    { 435, 5608 }, { 436, 5672 }, { 437, 5748 }, { 438, 5835 }, { 439, 5932 },
                    { 440, 6041 }, { 441, 6096 }, { 442, 6151 }, { 443, 6205 }, { 444, 6257 },
                    { 445, 6309 }, { 446, 6360 }, { 447, 6410 }, { 448, 6459 }, { 449, 6507 },
                    { 450, 6553 }, { 451, 6598 }, { 452, 6642 }, { 453, 6684 }, { 454, 6725 },
                    { 455, 6764 }, { 456, 6802 }, { 457, 6838 }, { 458, 6873 }, { 459, 6906 },
                    { 460, 6937 }, { 461, 6967 }, { 462, 6994 }, { 463, 7020 }, { 464, 7044 },
                    { 465, 7066 }, { 466, 7087 }, { 467, 7105 }, { 468, 7121 }, { 469, 7136 },
                    { 470, 7148 }, { 471, 6989 }, { 472, 6826 }, { 473, 6660 }, { 474, 6491 },
                    { 475, 6320 }, { 476, 6149 }, { 477, 5976 }, { 478, 5804 }, { 479, 5632 },
                    { 480, 8191 }
                };
                Assert.AreEqual(expectedPit.Count, pitchBend.size());
                int i = 0;
                foreach (var pitInfo in expectedPit)
                {
                    Assert.AreEqual(pitInfo.Key, pitchBend.getKeyClock(i));
                    Assert.AreEqual(pitInfo.Value, pitchBend.getElementA(i));
                    ++i;
                }
            }

            {
                var expectedPbs = new Dictionary <int, int> {
                    { 0, 2 }, { 430, 3 }, { 480, 2 }
                };
                Assert.AreEqual(expectedPbs.Count, pitchBendSensitivity.size());
                int i = 0;
                foreach (var pbsInfo in expectedPbs)
                {
                    Assert.AreEqual(pbsInfo.Key, pitchBendSensitivity.getKeyClock(i));
                    Assert.AreEqual(pbsInfo.Value, pitchBendSensitivity.getElementA(i));
                    ++i;
                }
            }
        }
 public void reflectVibratoPitch(VsqEvent item, VsqBPList pitchBend, VsqBPList pitchBendSensitivity, TempoVector tempoTable)
 {
     base.reflectNoteEventPitch(item, pitchBend, pitchBendSensitivity, tempoTable);
 }
Ejemplo n.º 14
0
        /// <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);
        }
        /// <summary>
        /// 音符に付随するピッチベンドの情報を、PIT・PBS カーブに反映する
        /// </summary>
        /// <param name="item">音符</param>
        /// <param name="pitchBend">PIT カーブ</param>
        /// <param name="pitchBendSensitivity">PBS カーブ</param>
        /// <param name="tempoTable">テンポ情報</param>
        protected void reflectNoteEventPitch(VsqEvent item, VsqBPList pitchBend, VsqBPList pitchBendSensitivity, TempoVector tempoTable)
        {
            if (item.ID.type != VsqIDType.Anote)
            {
                return;
            }

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

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

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

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

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

            bool   resetPBS = false;
            double maxNetPitchBendInCent = 0.0;

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

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

            if (!resetPBS)
            {
                return;
            }

            pitchBend.Data = pitBackup.Data;

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

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

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

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

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

                const double pow2_13            = 8192;
                double       netPitchBendInCent = (pbs * pit / pow2_13) * 100.0 + vibratoPitchBendInCent;
                maxNetPitchBendInCent = Math.Max(maxNetPitchBendInCent, Math.Abs(netPitchBendInCent));
                int draftPitchBend = (int)Math.Round((netPitchBendInCent / 100.0) * pow2_13 / requiredPitchbendSensitivity);
                if (draftPitchBend < pitchBend.Minimum)
                {
                    draftPitchBend = pitchBend.Minimum;
                }
                if (pitchBend.Maximum < draftPitchBend)
                {
                    draftPitchBend = pitchBend.Maximum;
                }
                if (draftPitchBend != lastPitchBend)
                {
                    pitchBend.add(clock, draftPitchBend);
                    lastPitchBend = draftPitchBend;
                }
            }
        }
Ejemplo n.º 16
0
 private static void copyCurve( VsqBPList src, VsqBPList dest, int clock_shift ){
     int last_value = src.getDefault();
     int count = src.size();
     bool first_over_zero = true;
     for( int i = 0; i < count; i++ ){
         int cl = src.getKeyClock( i ) - clock_shift;
         int value = src.getElementA( i );
         if( cl < 0 ){
             last_value = value;
         }else{
             if( first_over_zero ){
                 first_over_zero = false;
                 if( last_value != src.getDefault() ){
                     dest.add( 0, last_value );
                 }
             }
             dest.add( cl, value );
         }
     }
 }
Ejemplo n.º 17
0
    public static ScriptReturnStatus Edit(VsqFileEx vsq)
    {
        // 選択状態のアイテムがなければ戻る
        if (AppManager.itemSelection.getEventCount() <= 0)
        {
            return(ScriptReturnStatus.NOT_EDITED);
        }

        // 現在のトラック
        int      selected  = AppManager.getSelected();
        VsqTrack vsq_track = vsq.Track.get(selected);

        vsq_track.sortEvent();

        // プラグイン情報の定義ファイル(plugin.txt)があるかどうかチェック
        string pluginTxtPath = s_plugin_txt_path;

        if (pluginTxtPath == "")
        {
            AppManager.showMessageBox("pluginTxtPath=" + pluginTxtPath);
            return(ScriptReturnStatus.ERROR);
        }
        if (!System.IO.File.Exists(pluginTxtPath))
        {
            AppManager.showMessageBox("'" + pluginTxtPath + "' does not exists");
            return(ScriptReturnStatus.ERROR);
        }

        // plugin.txtがあれば,プラグインの実行ファイルのパスを取得する
        System.Text.Encoding shift_jis = System.Text.Encoding.GetEncoding("Shift_JIS");
        string name     = "";
        string exe_path = "";

        using (StreamReader sr = new StreamReader(pluginTxtPath, shift_jis)) {
            string line = "";
            while ((line = sr.ReadLine()) != null)
            {
                string[] spl = line.Split(new char[] { '=' }, StringSplitOptions.RemoveEmptyEntries);
                if (line.StartsWith("name="))
                {
                    name = spl[1];
                }
                else if (line.StartsWith("execute="))
                {
                    exe_path = Path.Combine(Path.GetDirectoryName(pluginTxtPath), spl[1]);
                }
            }
        }
        if (exe_path == "")
        {
            return(ScriptReturnStatus.ERROR);
        }
        if (!System.IO.File.Exists(exe_path))
        {
            AppManager.showMessageBox("'" + exe_path + "' does not exists");
            return(ScriptReturnStatus.ERROR);
        }

        // 選択状態のアイテムの最初と最後がどこか調べる
        // clock_start, clock_endは,最終的にはPREV, NEXTを含んだ範囲を表すことになる
        // sel_start, sel_endはPREV, NEXTを含まない選択範囲を表す
        int id_start    = -1;
        int clock_start = int.MaxValue;
        int id_end      = -1;
        int clock_end   = int.MinValue;
        int sel_start   = 0;
        int sel_end     = 0;

        for (Iterator <SelectedEventEntry> itr = AppManager.itemSelection.getEventIterator(); itr.hasNext();)
        {
            SelectedEventEntry item = itr.next();
            if (item.original.ID.type != VsqIDType.Anote)
            {
                continue;
            }
            int clock = item.original.Clock;
            if (clock < clock_start)
            {
                id_start    = item.original.InternalID;
                clock_start = clock;
                sel_start   = clock;
            }
            clock += item.original.ID.getLength();
            if (clock_end < clock)
            {
                id_end    = item.original.InternalID;
                clock_end = clock;
                sel_end   = clock;
            }
        }

        // 選択範囲の前後の音符を探す
        VsqEvent ve_prev = null;
        VsqEvent ve_next = null;
        VsqEvent l       = null;

        for (Iterator <VsqEvent> itr = vsq_track.getNoteEventIterator(); itr.hasNext();)
        {
            VsqEvent item = itr.next();
            if (item.InternalID == id_start)
            {
                if (l != null)
                {
                    ve_prev = l;
                }
            }
            if (l != null)
            {
                if (l.InternalID == id_end)
                {
                    ve_next = item;
                }
            }
            l = item;
            if (ve_prev != null && ve_next != null)
            {
                break;
            }
        }
        int  next_rest_clock = -1;
        bool prev_is_rest    = false;

        if (ve_prev != null)
        {
            // 直前の音符がある場合
            if (ve_prev.Clock + ve_prev.ID.getLength() == clock_start)
            {
                // 接続している
                clock_start = ve_prev.Clock;
            }
            else
            {
                // 接続していない
                int new_clock_start = ve_prev.Clock + ve_prev.ID.getLength();
                clock_start = new_clock_start;
            }
        }
        else
        {
            // 無い場合
            if (vsq.getPreMeasureClocks() < clock_start)
            {
                prev_is_rest = true;
            }
            int new_clock_start = vsq.getPreMeasureClocks();
            clock_start = new_clock_start;
        }
        if (ve_next != null)
        {
            // 直後の音符がある場合
            if (ve_next.Clock == clock_end)
            {
                // 接続している
                clock_end = ve_next.Clock + ve_next.ID.getLength();
            }
            else
            {
                // 接続していない
                next_rest_clock = clock_end;
                clock_end       = ve_next.Clock;
            }
        }

        // 作業用のVSQに,選択範囲のアイテムを格納
        VsqFileEx v = (VsqFileEx)vsq.clone();// new VsqFile( "Miku", 1, 4, 4, 500000 );

        // 選択トラックだけ残して他を削る
        for (int i = 1; i < selected; i++)
        {
            v.Track.removeElementAt(1);
        }
        for (int i = selected + 1; i < v.Track.size(); i++)
        {
            v.Track.removeElementAt(selected + 1);
        }
        // 選択トラックの音符を全消去する
        VsqTrack v_track = v.Track.get(1);

        v_track.MetaText.getEventList().clear();
        for (Iterator <VsqEvent> itr = vsq_track.getNoteEventIterator(); itr.hasNext();)
        {
            VsqEvent item = itr.next();
            if (clock_start <= item.Clock && item.Clock + item.ID.getLength() <= clock_end)
            {
                v_track.addEvent((VsqEvent)item.clone(), item.InternalID);
            }
        }
        // 最後のRを手動で追加.これは自動化できない
        if (next_rest_clock != -1)
        {
            VsqEvent item = (VsqEvent)ve_next.clone();
            item.ID.LyricHandle.L0.Phrase = "R";
            item.Clock = next_rest_clock;
            item.ID.setLength(clock_end - next_rest_clock);
            v_track.addEvent(item);
        }
        // 0~選択範囲の開始位置までを削除する
        v.removePart(0, clock_start);

        // vsq -> ustに変換
        // キーがustのIndex, 値がInternalID
        TreeMap <int, int> map = new TreeMap <int, int>();
        UstFile            u   = new UstFile(v, 1, map);

        u.write(Path.Combine(PortUtil.getApplicationStartupPath(), "u.ust"));

        // PREV, NEXTのIndex値を設定する
        if (ve_prev != null || prev_is_rest)
        {
            u.getTrack(0).getEvent(0).Index = UstFile.PREV_INDEX;
        }
        if (ve_next != null)
        {
            u.getTrack(0).getEvent(u.getTrack(0).getEventCount() - 1).Index = UstFile.NEXT_INDEX;
        }

        // ustファイルに出力
        UstFileWriteOptions option = new UstFileWriteOptions();

        option.settingCacheDir    = false;
        option.settingOutFile     = false;
        option.settingProjectName = false;
        option.settingTempo       = true;
        option.settingTool1       = true;
        option.settingTool2       = true;
        option.settingTracks      = false;
        option.settingVoiceDir    = true;
        option.trackEnd           = false;
        string temp = Path.GetTempFileName();

        u.write(temp, option);

        StringBuilder before = new StringBuilder();

        using (StreamReader sr = new StreamReader(temp, System.Text.Encoding.GetEncoding("Shift_JIS"))) {
            string line = "";
            while ((line = sr.ReadLine()) != null)
            {
                before.AppendLine(line);
            }
        }
        String md5_before = PortUtil.getMD5FromString(before.ToString());
        // プラグインの実行ファイルを起動
        Utau_Plugin_Invoker dialog = new Utau_Plugin_Invoker(exe_path, temp);

        dialog.ShowDialog();
        StringBuilder after = new StringBuilder();

        using (StreamReader sr = new StreamReader(temp, System.Text.Encoding.GetEncoding("Shift_JIS"))) {
            string line = "";
            while ((line = sr.ReadLine()) != null)
            {
                after.AppendLine(line);
            }
        }
        String md5_after = PortUtil.getMD5FromString(after.ToString());

        if (md5_before == md5_after)
        {
            // 編集されなかったようだ
            return(ScriptReturnStatus.NOT_EDITED);
        }

        // プラグインの実行結果をustオブジェクトにロード
        UstFile r = new UstFile(temp);

        if (r.getTrackCount() < 1)
        {
            return(ScriptReturnStatus.ERROR);
        }

        // 変更のなかったものについてはプラグインは記録してこないので,
        // 最初の値を代入するようにする
        UstTrack utrack_src = u.getTrack(0);
        UstTrack utrack_dst = r.getTrack(0);

        for (int i = 0; i < utrack_dst.getEventCount(); i++)
        {
            UstEvent ue_dst = utrack_dst.getEvent(i);
            int      index  = ue_dst.Index;
            UstEvent ue_src = utrack_src.findEventFromIndex(index);
            if (ue_src == null)
            {
                continue;
            }
            if (!ue_dst.isEnvelopeSpecified() && ue_src.isEnvelopeSpecified())
            {
                ue_dst.setEnvelope(ue_src.getEnvelope());
            }
            if (!ue_dst.isIntensitySpecified() && ue_src.isIntensitySpecified())
            {
                ue_dst.setIntensity(ue_src.getIntensity());
            }
            if (!ue_dst.isLengthSpecified() && ue_src.isLengthSpecified())
            {
                ue_dst.setLength(ue_src.getLength());
            }
            if (!ue_dst.isLyricSpecified() && ue_src.isLyricSpecified())
            {
                ue_dst.setLyric(ue_src.getLyric());
            }
            if (!ue_dst.isModurationSpecified() && ue_src.isModurationSpecified())
            {
                ue_dst.setModuration(ue_src.getModuration());
            }
            if (!ue_dst.isNoteSpecified() && ue_src.isNoteSpecified())
            {
                ue_dst.setNote(ue_src.getNote());
            }
            if (!ue_dst.isPBTypeSpecified() && ue_src.isPBTypeSpecified())
            {
                ue_dst.setPBType(ue_src.getPBType());
            }
            if (!ue_dst.isPitchesSpecified() && ue_src.isPitchesSpecified())
            {
                ue_dst.setPitches(ue_src.getPitches());
            }
            if (!ue_dst.isPortamentoSpecified() && ue_src.isPortamentoSpecified())
            {
                ue_dst.setPortamento(ue_src.getPortamento());
            }
            if (!ue_dst.isPreUtteranceSpecified() && ue_src.isPreUtteranceSpecified())
            {
                ue_dst.setPreUtterance(ue_src.getPreUtterance());
            }
            if (!ue_dst.isStartPointSpecified() && ue_src.isStartPointSpecified())
            {
                ue_dst.setStartPoint(ue_src.getStartPoint());
            }
            if (!ue_dst.isTempoSpecified() && ue_src.isTempoSpecified())
            {
                ue_dst.setTempo(ue_src.getTempo());
            }
            if (!ue_dst.isVibratoSpecified() && ue_src.isVibratoSpecified())
            {
                ue_dst.setVibrato(ue_src.getVibrato());
            }
            if (!ue_dst.isVoiceOverlapSpecified() && ue_src.isVoiceOverlapSpecified())
            {
                ue_dst.setVoiceOverlap(ue_src.getVoiceOverlap());
            }
        }

        // PREVとNEXT含めて,clock_startからclock_endまでプラグインに渡したけれど,
        // それが伸びて帰ってきたか縮んで帰ってきたか.
        int      ret_length = 0;
        UstTrack r_track    = r.getTrack(0);
        int      size       = r_track.getEventCount();

        for (int i = 0; i < size; i++)
        {
            UstEvent ue = r_track.getEvent(i);
            // 戻りのustには,変更があったものしか記録されていない
            int ue_length = ue.getLength();
            if (!ue.isLengthSpecified() && map.ContainsKey(ue.Index))
            {
                int      internal_id = map[ue.Index];
                VsqEvent found_item  = vsq_track.findEventFromID(internal_id);
                if (found_item != null)
                {
                    ue_length = found_item.ID.getLength();
                }
            }
            // PREV, ENDの場合は長さに加えない
            if (ue.Index != UstFile.NEXT_INDEX &&
                ue.Index != UstFile.PREV_INDEX)
            {
                ret_length += ue_length;
            }
        }

        // 伸び縮みがあった場合
        // 伸ばしたり縮めたりするよ
        int delta = ret_length - (sel_end - sel_start);

        if (delta > 0)
        {
            // のびた
            vsq.insertBlank(selected, sel_end, delta);
        }
        else if (delta < 0)
        {
            // 縮んだ
            vsq.removePart(selected, sel_end + delta, sel_end);
        }

        // r_trackの内容をvsq_trackに転写
        size = r_track.getEventCount();
        int c = clock_start;

        for (int i = 0; i < size; i++)
        {
            UstEvent ue = r_track.getEvent(i);
            if (ue.Index == UstFile.NEXT_INDEX || ue.Index == UstFile.PREV_INDEX)
            {
                // PREVとNEXTは単に無視する
                continue;
            }
            int ue_length = ue.getLength();
            if (map.containsKey(ue.Index))
            {
                // 既存の音符の編集
                VsqEvent target = vsq_track.findEventFromID(map[ue.Index]);
                if (target == null)
                {
                    // そんなばかな・・・
                    continue;
                }
                if (!ue.isLengthSpecified())
                {
                    ue_length = target.ID.getLength();
                }
                if (target.UstEvent == null)
                {
                    target.UstEvent = (UstEvent)ue.clone();
                }
                // utau固有のパラメータを転写
                // pitchは後でやるので無視していい
                // テンポもあとでやるので無視していい
                if (ue.isEnvelopeSpecified())
                {
                    target.UstEvent.setEnvelope(ue.getEnvelope());
                }
                if (ue.isModurationSpecified())
                {
                    target.UstEvent.setModuration(ue.getModuration());
                }
                if (ue.isPBTypeSpecified())
                {
                    target.UstEvent.setPBType(ue.getPBType());
                }
                if (ue.isPortamentoSpecified())
                {
                    target.UstEvent.setPortamento(ue.getPortamento());
                }
                if (ue.isPreUtteranceSpecified())
                {
                    target.UstEvent.setPreUtterance(ue.getPreUtterance());
                }
                if (ue.isStartPointSpecified())
                {
                    target.UstEvent.setStartPoint(ue.getStartPoint());
                }
                if (ue.isVibratoSpecified())
                {
                    target.UstEvent.setVibrato(ue.getVibrato());
                }
                if (ue.isVoiceOverlapSpecified())
                {
                    target.UstEvent.setVoiceOverlap(ue.getVoiceOverlap());
                }
                // vocaloid, utauで同じ意味のパラメータを転写
                if (ue.isIntensitySpecified())
                {
                    target.UstEvent.setIntensity(ue.getIntensity());
                    target.ID.Dynamics = ue.getIntensity();
                }
                if (ue.isLengthSpecified())
                {
                    target.UstEvent.setLength(ue.getLength());
                    target.ID.setLength(ue.getLength());
                }
                if (ue.isLyricSpecified())
                {
                    target.UstEvent.setLyric(ue.getLyric());
                    target.ID.LyricHandle.L0.Phrase = ue.getLyric();
                }
                if (ue.isNoteSpecified())
                {
                    target.UstEvent.setNote(ue.getNote());
                    target.ID.Note = ue.getNote();
                }
            }
            else
            {
                // マップに入っていないので,新しい音符の追加だと思う
                if (ue.getLyric() == "R")
                {
                    // 休符.なにもしない
                }
                else
                {
                    VsqEvent newe = new VsqEvent();
                    newe.Clock    = c;
                    newe.UstEvent = (UstEvent)ue.clone();
                    newe.ID       = new VsqID();
                    AppManager.editorConfig.applyDefaultSingerStyle(newe.ID);
                    if (ue.isIntensitySpecified())
                    {
                        newe.ID.Dynamics = ue.getIntensity();
                    }
                    newe.ID.LyricHandle = new LyricHandle("あ", "a");
                    if (ue.isLyricSpecified())
                    {
                        newe.ID.LyricHandle.L0.Phrase = ue.getLyric();
                    }
                    newe.ID.Note = ue.getNote();
                    newe.ID.setLength(ue.getLength());
                    newe.ID.type = VsqIDType.Anote;
                    // internal id はaddEventメソッドで自動で割り振られる
                    vsq_track.addEvent(newe);
                }
            }

            // テンポの追加がないかチェック
            if (ue.isTempoSpecified())
            {
                insertTempoInto(vsq, c, ue.getTempo());
            }

            c += ue_length;
        }

        // ピッチを転写
        // pitのデータがほしいので,PREV, NEXTを削除して,VsqFileにコンバートする
        UstFile uf = (UstFile)r.clone();
        // prev, nextを削除
        UstTrack uf_track = uf.getTrack(0);

        for (int i = 0; i < uf_track.getEventCount();)
        {
            UstEvent ue = uf_track.getEvent(i);
            if (ue.Index == UstFile.NEXT_INDEX ||
                ue.Index == UstFile.PREV_INDEX)
            {
                uf_track.removeEventAt(i);
            }
            else
            {
                i++;
            }
        }
        uf.updateTempoInfo();
        // VsqFileにコンバート
        VsqFile uf_vsq = new VsqFile(uf);

        // uf_vsqの最初のトラックの0からret_lengthクロックまでが,
        // vsq_trackのsel_startからsel_start+ret_lengthクロックまでに対応する.
        // まずPBSをコピーする
        CurveType[] type = new CurveType[] { CurveType.PBS, CurveType.PIT };
        foreach (CurveType ct in type)
        {
            // コピー元を取得
            VsqBPList src = uf_vsq.Track[1].getCurve(ct.getName());
            if (src != null)
            {
                // コピー先を取得
                VsqBPList dst = vsq_track.getCurve(ct.getName());
                if (dst == null)
                {
                    // コピー先がnullだった場合は作成
                    dst = new VsqBPList(ct.getName(), ct.getDefault(), ct.getMinimum(), ct.getMaximum());
                    vsq_track.setCurve(ct.getName(), dst);
                }
                // あとで復元するので,最終位置での値を保存しておく
                int value_at_end = dst.getValue(sel_start + ret_length);
                // 復元するかどうか.最終位置にそもそもデータ点があれば復帰の必要がないので.
                bool do_revert = (dst.findIndexFromClock(sel_start + ret_length) < 0);
                // [sel_start, sel_start + ret_length)の範囲の値を削除しておく
                size = dst.size();
                for (int i = size - 1; i >= 0; i--)
                {
                    int cl = dst.getKeyClock(i);
                    if (sel_start <= cl && cl < sel_start + ret_length)
                    {
                        dst.removeElementAt(i);
                    }
                }
                // コピーを実行
                size = src.size();
                for (int i = 0; i < size; i++)
                {
                    int cl = src.getKeyClock(i);
                    if (ret_length <= cl)
                    {
                        break;
                    }
                    int value = src.getElementA(i);
                    dst.add(cl + sel_start, value);
                }
                // コピー後,最終位置での値が元と異なる場合,元に戻すようにする
                if (do_revert && dst.getValue(sel_start + ret_length) != value_at_end)
                {
                    dst.add(sel_start + ret_length, value_at_end);
                }
            }
        }

        return(ScriptReturnStatus.EDITED);
    }
Ejemplo n.º 18
0
        public void commonButton_Click(Object sender, EventArgs e)
        {
            VsqBPList list = AppManager.getVsqFile().Track[AppManager.getSelected()].getCurve(m_curve.getName());
            VsqBPPairSearchContext search = list.findElement(m_editing_id);
            int index = search.index;

            if (sender == btnForward)
            {
                index++;
            }
            else if (sender == btnBackward)
            {
                index--;
            }
            else if (sender == btnBackward2)
            {
                index -= 5;
            }
            else if (sender == btnForward2)
            {
                index += 5;
            }
            else if (sender == btnForward3)
            {
                index += 10;
            }
            else if (sender == btnBackward3)
            {
                index -= 10;
            }

            if (index < 0)
            {
                index = 0;
            }

            if (list.size() <= index)
            {
                index = list.size() - 1;
            }

            VsqBPPair bp = list.getElementB(index);

            m_editing_id = bp.id;
            int clock = list.getKeyClock(index);

            txtDataPointClock.TextChanged -= commonTextBox_TextChanged;
            txtDataPointValue.TextChanged -= commonTextBox_TextChanged;
            txtDataPointClock.Text         = clock + "";
            txtDataPointValue.Text         = bp.value + "";
            txtDataPointClock.TextChanged += commonTextBox_TextChanged;
            txtDataPointValue.TextChanged += commonTextBox_TextChanged;

            txtDataPointValue.Focus();
            txtDataPointValue.SelectAll();

            AppManager.itemSelection.clearPoint();
            AppManager.itemSelection.addPoint(m_curve, bp.id);
            if (mMainWindow != null)
            {
                mMainWindow.ensureVisible(clock);
                mMainWindow.refreshScreen();
            }
        }