Ejemplo n.º 1
0
        /// <summary>
        /// 指定した位置に,指定した量の空白を挿入します
        /// </summary>
        /// <param name="clock_start">空白を挿入する位置</param>
        /// <param name="clock_amount">挿入する空白の量</param>
        public void insertBlank(int clock_start, int clock_amount)
        {
            // イベントをシフト
            for (Iterator <VsqEvent> itr = getEventIterator(); itr.hasNext();)
            {
                VsqEvent item = itr.next();
                if (item.ID.type == VsqIDType.Singer && item.Clock <= 0)
                {
                    continue;
                }
                if (clock_start <= item.Clock)
                {
                    item.Clock += clock_amount;
                }
            }

            // コントロールカーブをシフト
            foreach (string name in CURVES)
            {
                VsqBPList list = getCurve(name);
                if (list == null)
                {
                    continue;
                }

                // 後ろからシフトしないといけない
                int size = list.size();
                for (int i = size - 1; i >= 0; i--)
                {
                    int clock = list.getKeyClock(i);
                    if (clock_start <= clock)
                    {
                        int value = list.getElementA(i);
                        list.move(clock, clock + clock_amount, value);
                    }
                }
            }
        }
Ejemplo n.º 2
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);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// クレッシェンド,デクレッシェンド,および強弱記号をダイナミクスカーブに反映させます.
        /// この操作によって,ダイナミクスカーブに設定されたデータは全て削除されます.
        /// </summary>
        public void reflectDynamics()
        {
            VsqBPList dyn = getCurve("dyn");

            dyn.clear();
            for (Iterator <VsqEvent> itr = getDynamicsEventIterator(); itr.hasNext();)
            {
                VsqEvent           item   = itr.next();
                IconDynamicsHandle handle = item.ID.IconDynamicsHandle;
                if (handle == null)
                {
                    continue;
                }
                int clock  = item.Clock;
                int length = item.ID.getLength();

                if (handle.isDynaffType())
                {
                    // 強弱記号
                    dyn.add(clock, handle.getStartDyn());
                }
                else
                {
                    // クレッシェンド,デクレッシェンド
                    int start_dyn = dyn.getValue(clock);

                    // 範囲内のアイテムを削除
                    int count = dyn.size();
                    for (int i = count - 1; i >= 0; i--)
                    {
                        int c = dyn.getKeyClock(i);
                        if (clock <= c && c <= clock + length)
                        {
                            dyn.removeElementAt(i);
                        }
                        else if (c < clock)
                        {
                            break;
                        }
                    }

                    VibratoBPList bplist = handle.getDynBP();
                    if (bplist == null || (bplist != null && bplist.getCount() <= 0))
                    {
                        // カーブデータが無い場合
                        double a = 0.0;
                        if (length > 0)
                        {
                            a = (handle.getEndDyn() - handle.getStartDyn()) / (double)length;
                        }
                        int last_val = start_dyn;
                        for (int i = clock; i < clock + length; i++)
                        {
                            int val = start_dyn + (int)(a * (i - clock));
                            if (val < dyn.getMinimum())
                            {
                                val = dyn.getMinimum();
                            }
                            else if (dyn.getMaximum() < val)
                            {
                                val = dyn.getMaximum();
                            }
                            if (last_val != val)
                            {
                                dyn.add(i, val);
                                last_val = val;
                            }
                        }
                    }
                    else
                    {
                        // カーブデータがある場合
                        int last_val   = handle.getStartDyn();
                        int last_clock = clock;
                        int bpnum      = bplist.getCount();
                        int last       = start_dyn;

                        // bplistに指定されている分のデータ点を追加
                        for (int i = 0; i < bpnum; i++)
                        {
                            VibratoBPPair point      = bplist.getElement(i);
                            int           pointClock = clock + (int)(length * point.X);
                            if (pointClock <= last_clock)
                            {
                                continue;
                            }
                            int    pointValue = point.Y;
                            double a          = (pointValue - last_val) / (double)(pointClock - last_clock);
                            for (int j = last_clock; j <= pointClock; j++)
                            {
                                int val = start_dyn + (int)((j - last_clock) * a);
                                if (val < dyn.getMinimum())
                                {
                                    val = dyn.getMinimum();
                                }
                                else if (dyn.getMaximum() < val)
                                {
                                    val = dyn.getMaximum();
                                }
                                if (val != last)
                                {
                                    dyn.add(j, val);
                                    last = val;
                                }
                            }
                            last_val   = point.Y;
                            last_clock = pointClock;
                        }

                        // bplistの末尾から,clock => clock + lengthまでのデータ点を追加
                        int last2 = last;
                        if (last_clock < clock + length)
                        {
                            double a = (handle.getEndDyn() - last_val) / (double)(clock + length - last_clock);
                            for (int j = last_clock; j < clock + length; j++)
                            {
                                int val = last2 + (int)((j - last_clock) * a);
                                if (val < dyn.getMinimum())
                                {
                                    val = dyn.getMinimum();
                                }
                                else if (dyn.getMaximum() < val)
                                {
                                    val = dyn.getMaximum();
                                }
                                if (val != last)
                                {
                                    dyn.add(j, val);
                                    last = val;
                                }
                            }
                        }
                    }
                }
            }
        }