예제 #1
0
        public static VsqCommand generateCommandTrackReplace(int track, VsqTrack item)
        {
            VsqCommand command = new VsqCommand();

            command.Type    = VsqCommandType.TRACK_REPLACE;
            command.Args    = new Object[2];
            command.Args[0] = track;
            command.Args[1] = (VsqTrack)item.clone();
            return(command);
        }
예제 #2
0
    /// <summary>
    /// インターフェースIPaletteToolのメンバー
    /// </summary>
    /// <param name="track">編集対象のトラック</param>
    /// <param name="manager">Cadenciiのマネージャ</param>
    /// <param name="ids">クリックされたイベントのInternalIDが格納された配列</param>
    /// <param name="button">クリックされたときのマウスボタン</param>
    /// <returns></returns>
    public bool edit(cadencii.vsq.VsqTrack track, int[] ids, System.Windows.Forms.MouseButtons button)
    {
        // コントロールカーブの時間方向の解像度を,Cadenciiの設定値から取得
        int resol = AppManager.editorConfig.getControlCurveResolutionValue();

        for (int i = 0; i < ids.Length; i++)
        {
            int internal_id = ids[i];

            foreach (var item in track.getNoteEventIterator())
            {
                // 指定されたInternalIDと同じなら,編集する
                if (item.InternalID == internal_id)
                {
                    // Brightnessカーブを取得
                    cadencii.vsq.VsqBPList bri = track.getCurve("BRI");

                    // 音符の最後の位置でのBRIを取得.処理の最後で追加
                    int value_at_end = bri.getValue(item.Clock + item.ID.Length);

                    // これから編集しようとしている範囲にすでに値がある場合,邪魔なので削除する
                    bri.keyClockIterator()
                    .Where((clock) => item.Clock <= clock && clock <= item.Clock + item.ID.Length)
                    .ToList()
                    .ForEach((clock) => bri.remove(clock));

                    // 直前に指定したBRI値.最初はありえない値にしておく
                    int last_v = -1;

                    // 時間方向解像度(resol)ごとのクロックに対して,順次BRIを設定
                    for (int clock = item.Clock; clock <= item.Clock + item.ID.Length; clock += resol)
                    {
                        // BRIを取得.x=0が音符の先頭,x=1が音符の末尾.getCurve関数は,この仕様を満たすようにBRIを返すように,お好みで定義
                        float x = (clock - item.Clock) / (float)item.ID.Length;
                        int   v = getCurve(x);

                        if (last_v != v)
                        {
                            // 直前に指定した値と違うときだけ追加.
                            bri.add(clock, v);
                        }

                        // 「直前の値」を更新
                        last_v = v;
                    }

                    // 音符末尾の位置のBRIを強制的に元の値に戻す.これをやらないと,
                    // その音符の末尾以降のBRIがそのまま編集の影響を受けてしまう
                    bri.add(item.Clock + item.ID.Length, value_at_end);
                    break;
                }
            }
        }
        return(true);
    }
예제 #3
0
        /// <summary>
        /// トラックを追加するコマンドを発行します.trackはClone()して渡さなくてもよい
        /// </summary>
        /// <param name="track"></param>
        /// <returns></returns>
        public static VsqCommand generateCommandAddTrack(VsqTrack track, VsqMixerEntry mixer, int position)
        {
            VsqCommand command = new VsqCommand();

            command.Type    = VsqCommandType.TRACK_ADD;
            command.Args    = new Object[3];
            command.Args[0] = track;
            command.Args[1] = mixer;
            command.Args[2] = position;
            return(command);
        }
예제 #4
0
        /// <summary>
        /// このインスタンスのコピーを作成します
        /// </summary>
        /// <returns></returns>
        public Object clone()
        {
            VsqTrack res = new VsqTrack();

            res.SplitDictionaryName = this.SplitDictionaryName;
            res.setName(getName());
            if (MetaText != null)
            {
                res.MetaText = (VsqMetaText)MetaText.clone();
            }
            res.Tag = Tag;
            return(res);
        }
예제 #5
0
        /// <summary>
        /// vsqの指定したトラックを元に,トラックを1つだけ持つustを構築します
        /// </summary>
        /// <param name="vsq"></param>
        /// <param name="track_index"></param>
        /// <param name="id_map">UstEventのIndexフィールドと、元になったVsqEventのInternalIDを対応付けるマップ。キーがIndex、値がInternalIDを表す</param>
        public UstFile(VsqFile vsq, int track_index, SortedDictionary <int, int> id_map)
        {
            VsqFile work = (VsqFile)vsq.clone();
            //work.removePart( 0, work.getPreMeasureClocks() );

            VsqTrack vsq_track = work.Track[track_index];

            // デフォルトのテンポ
            if (work.TempoTable.Count <= 0)
            {
                m_tempo = 120.0f;
            }
            else
            {
                m_tempo = (float)(60e6 / (double)work.TempoTable[0].Tempo);
            }
            m_tempo_table = new List <TempoTableEntry>();
            m_tempo_table.Clear();
            // ustには、テンポチェンジを音符の先頭にしか入れられない
            // あとで音符に反映させるためのテンプレートを作っておく
            TempoVector tempo      = new TempoVector();
            int         last_clock = 0;
            int         itempo     = (int)(60e6 / m_tempo);

            foreach (var item in vsq_track.getNoteEventIterator())
            {
                if (last_clock < item.Clock)
                {
                    // 休符Rの分
                    tempo.Add(new TempoTableEntry(last_clock, itempo, work.getSecFromClock(last_clock)));
                }
                tempo.Add(new TempoTableEntry(item.Clock, itempo, work.getSecFromClock(item.Clock)));
                last_clock = item.Clock + item.ID.getLength();
            }
            if (tempo.Count == 0)
            {
                tempo.Add(new TempoTableEntry(0, (int)(60e6 / m_tempo), 0.0));
            }
            // tempoの中の各要素の時刻が、vsq.TempoTableから計算した時刻と合致するよう調節
#if DEBUG
            sout.println("UstFile#.ctor; before; list=");
            for (int i = 0; i < tempo.Count; i++)
            {
                TempoTableEntry item = tempo[i];
                sout.println("    #" + i + "; c" + item.Clock + "; T" + item.Tempo + "; t" + (60e6 / item.Tempo) + "; sec" + item.Time);
            }
#endif
            TempoTableEntry prev = tempo[0];
            for (int i = 1; i < tempo.Count; i++)
            {
                TempoTableEntry item  = tempo[i];
                double          sec   = item.Time - prev.Time;
                int             delta = item.Clock - prev.Clock;
                // deltaクロックでsecを表現するにはテンポをいくらにすればいいか?
                int draft = (int)(480.0 * sec * 1e6 / (double)delta);
                // 丸め誤差が入るので、Timeを更新
                // ustに実際に記録されるテンポはいくらか?
                float act_tempo   = (float)double.Parse(PortUtil.formatDecimal("0.00", 60e6 / draft));
                int   i_act_tempo = (int)(60e6 / act_tempo);
                prev.Tempo = i_act_tempo;
                item.Time  = prev.Time + 1e-6 * delta * prev.Tempo / 480.0;
                prev       = item;
            }
#if DEBUG
            sout.println("UstFile#.ctor; after; list=");
            for (int i = 0; i < tempo.Count; i++)
            {
                TempoTableEntry item = tempo[i];
                sout.println("    #" + i + "; c" + item.Clock + "; T" + item.Tempo + "; t" + (60e6 / item.Tempo) + "; sec" + item.Time);
            }
            sout.println("UstFile#.ctor; vsq.TempoTable=");
            for (int i = 0; i < work.TempoTable.Count; i++)
            {
                TempoTableEntry item = work.TempoTable[i];
                sout.println("    #" + i + "; c" + item.Clock + "; T" + item.Tempo + "; t" + (60e6 / item.Tempo) + "; sec" + item.Time);
            }
#endif

            // R用音符のテンプレート
            int      PBTYPE   = 5;
            UstEvent template = new UstEvent();
            template.setLyric("R");
            template.setNote(60);
            template.setPreUtterance(0);
            template.setVoiceOverlap(0);
            template.setIntensity(100);
            template.setModuration(0);

            // 再生秒時をとりあえず無視して,ゲートタイム基準で音符を追加
            UstTrack track_add = new UstTrack();
            last_clock = 0;
            int index = 0;
            foreach (var item in vsq_track.getNoteEventIterator())
            {
                if (last_clock < item.Clock)
                {
                    // ゲートタイム差あり,Rを追加
                    UstEvent itemust = (UstEvent)template.clone();
                    itemust.setLength(item.Clock - last_clock);
                    itemust.Index = index;
                    index++;
                    id_map[itemust.Index] = -1;
                    track_add.addEvent(itemust);
                }
                UstEvent item_add = (UstEvent)item.UstEvent.clone();
                item_add.setLength(item.ID.getLength());
                item_add.setLyric(item.ID.LyricHandle.L0.Phrase);
                item_add.setNote(item.ID.Note);
                item_add.Index         = index;
                id_map[item_add.Index] = item.InternalID;
                if (item.UstEvent.getEnvelope() != null)
                {
                    item_add.setEnvelope((UstEnvelope)item.UstEvent.getEnvelope().clone());
                }
                index++;
                track_add.addEvent(item_add);
                last_clock = item.Clock + item.ID.getLength();
            }

            // テンポを格納(イベント数はあっているはず)
            if (track_add.getEventCount() > 0)
            {
                int size      = track_add.getEventCount();
                int lasttempo = -1; // ありえない値にしておく
                for (int i = 0; i < size; i++)
                {
                    TempoTableEntry item = tempo[i];
                    if (lasttempo != item.Tempo)
                    {
                        // テンポ値が変わっているもののみ追加
                        UstEvent ue = track_add.getEvent(i);
                        ue.setTempo((float)(60e6 / item.Tempo));
                        lasttempo = item.Tempo;
                        m_tempo_table.Add(item);
                    }
                }
            }
            else
            {
                // tempoはどうせ破棄されるのでクローンしなくていい
                m_tempo_table.Add(tempo[0]);
            }

            // ピッチを反映
            // まず絶対ピッチを取得
            VsqBPList abs_pit     = new VsqBPList("", 600000, 0, 1280000);
            VsqBPList cpit        = vsq_track.getCurve("pit");
            int       clock       = 0;
            int       search_indx = 0;
            int       pit_size    = cpit.size();
            foreach (var item in track_add.getNoteEventIterator())
            {
                int c   = clock;
                int len = item.getLength();
                clock += len;
                if (item.getLyric() == "R")
                {
                    continue;
                }
                // 音符の先頭のpitは必ず入れる
                abs_pit.add(c, (int)(item.getNote() * 10000 + vsq_track.getPitchAt(c) * 100));

                // c~c+lenまで
                for (int i = search_indx; i < pit_size; i++)
                {
                    int c2 = cpit.getKeyClock(i);
                    if (c < c2 && c2 < clock)
                    {
                        abs_pit.add(c2, (int)(item.getNote() * 10000 + vsq_track.getPitchAt(c2) * 100));
                        search_indx = i;
                    }
                    else if (clock <= c2)
                    {
                        break;
                    }
                }
            }

            // ピッチをピッチベンドに変換しながら反映
            clock = 0;
            foreach (var item in track_add.getNoteEventIterator())
            {
                double sec_at_clock = tempo.getSecFromClock(clock);
                double sec_pre      = item.getPreUtterance() / 1000.0;
                double sec_stp      = item.getStartPoint() / 1000.0;
                double sec_at_begin = sec_at_clock - sec_pre - sec_stp;
                int    clock_begin  = (int)tempo.getClockFromSec(sec_at_begin);
                // 音符先頭との距離がPBTYPEの倍数になるようにする
                clock_begin -= (clock < clock_begin) ? ((clock_begin - clock) % PBTYPE)
                                                     : ((clock - clock_begin) % PBTYPE);
                // clock_beginがsec_at_beginより前方になるとNGなので修正する
                double sec_at_clock_begin = tempo.getSecFromClock(clock_begin);
                while (sec_at_clock_begin < sec_at_begin)
                {
                    clock_begin       += PBTYPE;
                    sec_at_clock_begin = tempo.getSecFromClock(clock_begin);
                }
                int          clock_end = clock + item.getLength();
                List <float> pitch     = new List <float>();
                bool         allzero   = true;
                ByRef <int>  ref_indx  = new ByRef <int>(0);
                for (int cl = clock_begin; cl < clock_end; cl += PBTYPE)
                {
                    int   abs = abs_pit.getValue(cl, ref_indx);
                    float pit = (float)(abs / 100.0) - item.getNote() * 100;
                    if (pit != 0.0)
                    {
                        allzero = false;
                    }
                    pitch.Add(pit);
                }
                if (!allzero)
                {
                    item.setPitches(PortUtil.convertFloatArray(pitch.ToArray()));
                    item.setPBType(PBTYPE);
                }
                else
                {
                    item.setPBType(-1);
                }
                clock += item.getLength();
            }

            m_tracks.Add(track_add);
        }
예제 #6
0
    public static bool Edit(cadencii.vsq.VsqFile vsq)
    {
        // 選択されているアイテム(のInternalID)をリストアップ
        System.Collections.Generic.List <int> ids = new System.Collections.Generic.List <int>();
        for (Iterator <SelectedEventEntry> itr = AppManager.itemSelection.getEventIterator(); itr.hasNext();)
        {
            SelectedEventEntry entry = itr.next();
            ids.Add(entry.original.InternalID);
        }

        cadencii.vsq.VsqTrack track = vsq.Track.get(AppManager.getSelected());

        // コントロールカーブの時間方向の解像度を,Cadenciiの設定値から取得
        int resol = AppManager.editorConfig.getControlCurveResolutionValue();

        for (int i = 0; i < ids.Count; i++)
        {
            int internal_id = ids[i];

            for (Iterator <VsqEvent> itr = track.getNoteEventIterator(); itr.hasNext();)
            {
                cadencii.vsq.VsqEvent item = itr.next();
                // 指定されたInternalIDと同じなら,編集する
                if (item.InternalID == internal_id)
                {
                    // Brightnessカーブを取得
                    cadencii.vsq.VsqBPList bri = track.getCurve("BRI");

                    // 音符の最後の位置でのBRIを取得.処理の最後で追加
                    int value_at_end = bri.getValue(item.Clock + item.ID.Length);

                    // これから編集しようとしている範囲にすでに値がある場合,邪魔なので削除する
                    for (Iterator <int> itr2 = bri.keyClockIterator(); itr.hasNext();)
                    {
                        int clock = itr2.next();
                        System.Console.WriteLine("clock=" + clock);
                        if (item.Clock <= clock && clock <= item.Clock + item.ID.Length)
                        {
                            itr2.remove();
                        }
                    }

                    // 直前に指定したBRI値.最初はありえない値にしておく
                    int last_v = -1;

                    // 時間方向解像度(resol)ごとのクロックに対して,順次BRIを設定
                    for (int clock = item.Clock; clock <= item.Clock + item.ID.Length; clock += resol)
                    {
                        // BRIを取得.x=0が音符の先頭,x=1が音符の末尾.getCurve関数は,この仕様を満たすようにBRIを返すように,お好みで定義
                        float x = (clock - item.Clock) / (float)item.ID.Length;
                        int   v = getCurve(x);

                        if (last_v != v)
                        {
                            // 直前に指定した値と違うときだけ追加.
                            bri.add(clock, v);
                        }

                        // 「直前の値」を更新
                        last_v = v;
                    }

                    // 音符末尾の位置のBRIを強制的に元の値に戻す.これをやらないと,
                    // その音符の末尾以降のBRIがそのまま編集の影響を受けてしまう
                    bri.add(item.Clock + item.ID.Length, value_at_end);
                    break;
                }
            }
        }
        return(true);
    }