public SingerEventComparisonContext(VsqTrack track1, VsqTrack track2) { this.track1 = track1; this.track2 = track2; it1 = this.track1.indexIterator(IndexIteratorKind.SINGER); it2 = this.track2.indexIterator(IndexIteratorKind.SINGER); }
/// <summary> /// 音符の note on/off のためのイベントを作成し、イベントキューに追加する /// </summary> /// <param name="track">生成元のトラック</param> /// <param name="result">生成したイベントの追加先</param> private void appendNoteEvent(VsqTrack track, EventQueueSequence result) { foreach (var item in track.MetaText.Events.Events) { if (item.ID.type != VsqIDType.Anote) { continue; } var note = item.ID.Note; { var clock = item.Clock; var queue = result.get(clock); var noteOn = driver_.createNoteOnEvent(item.ID.Note, item.ID.Dynamics, item.ID.LyricHandle.L0.Phrase); queue.noteon.AddRange(noteOn); } { var clock = item.Clock + item.ID.Length; var queue = result.get(clock); var noteOff = createNoteOffEvent(clock, item.ID.Note); queue.noteoff.add(noteOff); } } }
/// <summary> /// パレットツールを実行します /// </summary> /// <param name="id">実行するパレットツールのID</param> /// <param name="track">編集対象のトラック番号</param> /// <param name="vsq_event_intrenal_ids">編集対象のInternalIDのリスト</param> /// <param name="button">パレットツールが押し下げられた時のマウスボタンの種類</param> /// <returns>パレットツールによって編集が加えられた場合true。そうでなければfalse(パレットツールがエラーを起こした場合も含む)。</returns> public static boolean invokePaletteTool( String id, int track, int[] vsq_event_intrenal_ids, MouseButtons button ) { if ( loadedTools.containsKey( id ) ) { VsqFileEx vsq = AppManager.getVsqFile(); VsqTrack item = (VsqTrack)vsq.Track.get( track ).clone(); Object objPal = loadedTools.get( id ); if ( objPal == null ) { return false; } if ( !(objPal is IPaletteTool) ) { return false; } IPaletteTool pal = (IPaletteTool)objPal; boolean edited = false; try { edited = pal.edit( item, vsq_event_intrenal_ids, button ); } catch ( Exception ex ) { AppManager.showMessageBox( PortUtil.formatMessage( _( "Palette tool '{0}' reported an error.\nPlease copy the exception text and report it to developper." ), id ), "Error", cadencii.windows.forms.Utility.MSGBOX_DEFAULT_OPTION, cadencii.windows.forms.Utility.MSGBOX_ERROR_MESSAGE ); serr.println( typeof( PaletteToolServer ) + ".invokePaletteTool; ex=" + ex ); edited = false; } if ( edited ) { CadenciiCommand run = VsqFileEx.generateCommandTrackReplace( track, item, vsq.AttachedCurves.get( track - 1 ) ); AppManager.editHistory.register( vsq.executeCommand( run ) ); } return edited; } else { return false; } }
/// <summary> /// 選択中のアイテムが編集された場合、編集にあわせてオブジェクトを更新する。 /// </summary> public void updateSelectedEventInstance() { VsqFileEx vsq = AppManager.getVsqFile(); if (vsq == null) { return; } int selected = AppManager.getSelected(); VsqTrack vsq_track = vsq.Track[selected]; for (int i = 0; i < mEvents.Count; i++) { SelectedEventEntry item = mEvents[i]; VsqEvent ev = null; if (item.track == selected) { int internal_id = item.original.InternalID; ev = vsq_track.findEventFromID(internal_id); } if (ev != null) { mEvents[i] = new SelectedEventEntry(selected, ev, (VsqEvent)ev.clone()); } else { mEvents.RemoveAt(i); i--; } } }
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); }
private static void hamori(VsqFile vsq, int basecode, int opt) { int[][] steps = new int[][] { // C Major C D E F G A B // 7度上 new int[] { 11, 11, 10, 10, 10, 11, 11, 10, 10, 10, 10, 10 }, // 6度上 new int[] { 9, 9, 9, 9, 8, 9, 9, 9, 9, 8, 8, 9 }, // 5度上 new int[] { 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6 }, // 4度上 new int[] { 5, 5, 5, 5, 5, 6, 5, 5, 5, 5, 5, 5 }, // 3度上 new int[] { 4, 4, 3, 3, 3, 4, 4, 4, 4, 3, 3, 3 }, // 2度上 new int[] { 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 } }; int[] step; if (opt == 6) { return; } if (opt < 6) { step = steps[opt]; } else { step = steps[opt - 7]; for (int i = 0; i < 12; i++) { step[i] -= 12; } } int note, tmp; VsqTrack track = vsq.Track[AppManager.Selected]; for (Iterator <SelectedEventEntry> itr = AppManager.getSelectedEventIterator(); itr.hasNext();) { VsqEvent item = track.findEventFromID(((SelectedEventEntry)itr.next()).original.InternalID); if (item.ID.type == VsqIDType.Anote) { tmp = (item.ID.Note + 12 - basecode) % 12; note = item.ID.Note + step[tmp]; if (note < 0) { note = 0; } if (127 < note) { note = 127; } item.ID.Note = note; } } }
/// <summary> /// コンストラクタ。trackはcloneされないが、tempoはcloneされる。 /// </summary> /// <param name="track"></param> /// <param name="tempo"></param> public RenderedStatus(VsqTrack track, TempoVector tempo, SequenceConfig config) { this.track = track; this.tempo = new TempoVector(); foreach (var entry in tempo) { this.tempo.Add((TempoTableEntry)entry.clone()); } this.config = config; }
private XmlElement createTrackNode(VsqTrack track, int index, int pre_measure_clock, int sequence_length) { var result = doc_.CreateElement("vsTrack"); result.AppendChild(createNode("vsTrackNo", index)); result.AppendChild(createNode("trackName", track.getName())); result.AppendChild(createNode("comment", "")); result.AppendChild(createMusicalPartNode(track, pre_measure_clock, sequence_length)); return(result); }
/// <summary> /// ピッチとピッチベンドセンシティビティをイベントキューに追加する /// </summary> /// <param name="track"></param> /// <param name="sequence"></param> private void appendPitchEvent(VsqTrack track, EventQueueSequence sequence) { // 実際に AquesTone2 に送信する pbs の値と、pbs カーブに入っている値とのマップ const int maxPitchBendSensitivity = 23; int[] map = new int[maxPitchBendSensitivity + 1] { 0, 5, 15, 35, 44, 54, 64, 74, 84, 93, 103, 113, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, }; var pbs = track.MetaText.PBS; for (int i = 0; i < pbs.size(); ++i) { var clock = pbs.getKeyClock(i); { // RPN MSB = 0x00 var e = new MidiEvent(); e.firstByte = 0xB0; e.data = new int[] { 0x65, 0x00 }; e.clock = clock; sequence.get(clock).pit.add(e); } { // RPN LSB = 0x00 var e = new MidiEvent(); e.firstByte = 0xB0; e.data = new int[] { 0x64, 0x00 }; e.clock = clock; sequence.get(clock).pit.add(e); } { // RPN data MSB var e = new MidiEvent(); e.firstByte = 0xB0; int value = Math.Max(0, Math.Min(maxPitchBendSensitivity, pbs.getElementA(i))); e.data = new int[] { 0x06, map[value] }; e.clock = clock; sequence.get(clock).pit.add(e); } } var pit = track.MetaText.PIT; for (int i = 0; i < pit.size(); ++i) { var clock = pit.getKeyClock(i); var e = new MidiEvent(); e.firstByte = 0xE0; var value = pit.getElementA(i) + 8192; var msb = 0x7F & value; var lsb = 0x7F & (value >> 7); e.data = new int[] { msb, lsb }; sequence.get(clock).pit.add(e); } }
private List <TiedEvent> quantizeTrack(VsqTrack track, TimesigVector timesig_table, TempoVector tempo_table) { var result = new List <TiedEvent>(); if (track.MetaText == null) { return(result); } track.MetaText.Events.Events .AsParallel() .ForAll((item) => { if (item.ID != null) { var start_clock = quantize(item.Clock); var end_clock = quantize(item.Clock + item.ID.getLength()); item.Clock = start_clock; item.ID.setLength(end_clock - start_clock); } }); track.MetaText.Events.Events .RemoveAll((item) => { if (item.ID == null) { return(false); } return(item.ID.getLength() <= 0); }); int count = track.MetaText.Events.Events.Count; int clock = 0; for (int i = 0; i < count; ++i) { var item = track.MetaText.Events.Events[i]; if (item.ID.type == VsqIDType.Anote) { int rest_length = item.Clock - clock; if (rest_length > 0) { result.Add(new TiedEvent(clock, rest_length, timesig_table, tempo_table)); } result.Add(new TiedEvent(item, timesig_table, tempo_table)); clock = item.Clock + item.ID.getLength(); } } return(result); }
/// <summary> /// スクリプトの本体 /// </summary> /// <param name="vsq"></param> /// <returns></returns> public static ScriptReturnStatus Edit(VsqFileEx vsq) { int selected = AppManager.getSelected(); VsqTrack vsq_track = vsq.Track[selected]; RendererKind kind = VsqFileEx.getTrackRendererKind(vsq_track); if (kind != RendererKind.UTAU) { return(ScriptReturnStatus.NOT_EDITED); } bool edited = false; foreach (var item in AppManager.itemSelection.getEventIterator()) { VsqEvent original = item.original; if (original.ID.type != VsqIDType.Anote) { continue; } VsqEvent singer = vsq_track.getSingerEventAt(original.Clock); SingerConfig sc = AppManager.getSingerInfoUtau(singer.ID.IconHandle.Language, singer.ID.IconHandle.Program); if (sc != null && AppManager.mUtauVoiceDB.ContainsKey(sc.VOICEIDSTR)) { string phrase = original.ID.LyricHandle.L0.Phrase; UtauVoiceDB db = AppManager.mUtauVoiceDB[sc.VOICEIDSTR]; int CheckNote = original.ID.Note; if (original.UstEvent != null) { CheckNote = original.UstEvent.ReplaceNoteID > 0 ? original.UstEvent.ReplaceNoteID : original.ID.Note; } OtoArgs oa = db.attachFileNameFromLyric(phrase, CheckNote); VsqEvent editing = vsq_track.findEventFromID(original.InternalID); if (editing.UstEvent == null) { editing.UstEvent = new UstEvent(); } editing.UstEvent.setVoiceOverlap(oa.msOverlap); editing.UstEvent.setPreUtterance(oa.msPreUtterance); edited = true; } } return(edited ? ScriptReturnStatus.EDITED : ScriptReturnStatus.NOT_EDITED); }
/// <summary> /// 歌手変更イベントを、イベントキューに追加する /// </summary> /// <param name="queueSequence">追加対象のイベントキュー</param> /// <param name="track">歌手変更イベントを取り出すトラック</param> /// <param name="start">時間区間の開始位置</param> /// <param name="end">時間区間の終了位置</param> private void addSingerEvents(EventQueueSequence queueSequence, VsqTrack track, int start, int end) { var iterator = track.getSingerEventIterator(start, end); while (iterator.hasNext()) { var item = iterator.next(); if (item.ID.IconHandle == null) { continue; } int program = item.ID.IconHandle.Program; var singer = mDriver.createSingerEvent(program); if (0 < singer.Length) { var queue = queueSequence.get(item.Clock); queue.param.addAll(Arrays.asList(singer)); } } }
private XmlElement createMusicalPartNode(VsqTrack track, int pre_measure_clock, int sequence_length) { var result = doc_.CreateElement("musicalPart"); result.AppendChild(createNode("posTick", pre_measure_clock)); result.AppendChild(createNode("playTime", sequence_length - pre_measure_clock)); result.AppendChild(createNode("partName", track.getName())); result.AppendChild(createNode("comment", "")); { var stylePlugin = doc_.CreateElement("stylePlugin"); stylePlugin.AppendChild(createNode("stylePluginID", "ACA9C502-A04B-42b5-B2EB-5CEA36D16FCE")); stylePlugin.AppendChild(createNode("stylePluginName", "VOCALOID2 Compatible Style")); stylePlugin.AppendChild(createNode("version", "3.0.0.1")); result.AppendChild(stylePlugin); } { result.AppendChild(createPartStyleNode()); } // Set first singer var first_singer = (VsqEvent)track.getSingerEventAt(pre_measure_clock).Clone(); first_singer.Clock = pre_measure_clock; result.AppendChild(createMusicalPartSingerNode(first_singer, pre_measure_clock)); track.MetaText.Events.Events .Where((@event) => (@event.ID.type == VsqIDType.Singer ? @event.Clock > pre_measure_clock : @event.Clock >= pre_measure_clock)) .ToList() .ForEach((@event) => { if (@event.ID.type == VsqIDType.Singer) { var node = createMusicalPartSingerNode(@event, pre_measure_clock); result.AppendChild(node); } else if (@event.ID.type == VsqIDType.Anote) { result.AppendChild(createNoteNode(@event, pre_measure_clock)); } }); return(result); }
public static string FlagGener(VsqTrack track, VsqEvent item) { string SpecialI = item.UstEvent.Flags; int g = (track.MetaText.GEN.getValue(item.Clock + (item.ID.getLength() > 10 ? 10 : (item.ID.getLength() / 2))) - 64); int b = (track.MetaText.BRE.getValue(item.Clock + (item.ID.getLength() > 10 ? 10 : (item.ID.getLength() / 2))) - 64); if (SpecialI.IndexOf("g") < 0) { if (g != 0) { SpecialI = SpecialI + "g" + g.ToString(); } } if (SpecialI.IndexOf("BRE") < 0) { if (b != 0) { SpecialI = SpecialI + "BRE" + b.ToString(); } } return(SpecialI);// SpecialI.Replace("p", "popop") + " p0"; }
private static void transpose(VsqFile vsq, int step) { int note; VsqTrack track = vsq.Track[AppManager.Selected]; for (Iterator <SelectedEventEntry> itr = AppManager.getSelectedEventIterator(); itr.hasNext();) { VsqEvent item = track.findEventFromID(((SelectedEventEntry)itr.next()).original.InternalID); if (item.ID.type == VsqIDType.Anote) { note = item.ID.Note + step; if (note < 0) { note = 0; } if (127 < note) { note = 127; } item.ID.Note = note; } } }
private XmlElement createMasterTrackNode(VsqFile sequence, VsqTrack master_track) { var result = doc_.CreateElement("masterTrack"); result.AppendChild(createNode("seqName", master_track.getName())); result.AppendChild(createNode("comment", "")); result.AppendChild(createNode("resolution", sequence.getTickPerQuarter())); result.AppendChild(createNode("preMeasure", sequence.getPreMeasure())); sequence.TimesigTable.ForEach((time_sig) => { var node = doc_.CreateElement("timeSig"); node.AppendChild(createNode("posMes", time_sig.BarCount)); node.AppendChild(createNode("nume", time_sig.Numerator)); node.AppendChild(createNode("denomi", time_sig.Denominator)); result.AppendChild(node); }); sequence.TempoTable.ForEach((tempo) => { var node = doc_.CreateElement("tempo"); node.AppendChild(createNode("posTick", tempo.Clock)); node.AppendChild(createNode("bpm", (int)(60e6 / tempo.Tempo * 100))); result.AppendChild(node); }); return(result); }
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); }
/// <summary> /// vsqxファイルを読み込み,新しいシーケンスオブジェクトを生成する /// </summary> /// <param name="filePath">ファイルパス</param> /// <exception cref="System.Exception">読み込みに失敗した時スローされる</exception> /// <returns>生成したシーケンスオブジェクト</returns> public static VsqFile readFromVsqx(string filePath) { if (filePath == null) { throw new ArgumentNullException("filePath"); } if (false == File.Exists(filePath)) { throw new Exception("file not found"); } var xml = new XmlDocument(); xml.Load(filePath); // 音源テーブルを解釈 var voiceTable = getVoiceTable(xml); // マスタートラックを解釈 XmlElement masterTrack = xml.DocumentElement["masterTrack"]; int preMeasure = int.Parse(masterTrack["preMeasure"].InnerText); VsqFile result = new VsqFile("", preMeasure, 4, 4, 500000); // テンポ変更を読み取る result.TempoTable.Clear(); foreach (XmlNode node in masterTrack.GetElementsByTagName("tempo")) { int posTick = int.Parse(node["posTick"].InnerText); int bpm = int.Parse(node["bpm"].InnerText); int tempo = (int)(6000000000L / bpm); TempoTableEntry tempoEntry = new TempoTableEntry(posTick, tempo, 0.0); result.TempoTable.Add(tempoEntry); } result.TempoTable.updateTempoInfo(); // 拍子変更を読み取る result.TimesigTable.Clear(); foreach (XmlNode node in masterTrack.GetElementsByTagName("timeSig")) { int posMes = int.Parse(node["posMes"].InnerText); int numerator = int.Parse(node["nume"].InnerText); int denominator = int.Parse(node["denomi"].InnerText); TimeSigTableEntry timesigEntry = new TimeSigTableEntry(0, numerator, denominator, posMes); result.TimesigTable.Add(timesigEntry); } result.TimesigTable.updateTimesigInfo(); // マスター以外のトラックを解釈 foreach (XmlNode node in xml.DocumentElement.GetElementsByTagName("vsTrack")) { int trackIndex = int.Parse(node["vsTrackNo"].InnerText) + 1; VsqTrack track = null; if (result.Track.Count <= trackIndex) { int amount = trackIndex + 1 - result.Track.Count; for (int i = 0; i < amount; i++) { result.Track.Add(new VsqTrack("", "")); } } track = result.Track[trackIndex]; track.setName(node["trackName"].InnerText); foreach (XmlNode child in node.ChildNodes) { if (child.Name == "musicalPart") { parseMusicalPart(voiceTable, track, child); } } } // MasterMixerをパース var mixer = xml.DocumentElement["mixer"]; var masterUnit = mixer["masterUnit"]; result.Mixer.MasterFeder = int.Parse(masterUnit["vol"].InnerText); result.Mixer.MasterMute = 0; result.Mixer.MasterPanpot = 0; // SlaveMixerをパース result.Mixer.Slave.Clear(); for (int i = 1; i < result.Track.Count; i++) { result.Mixer.Slave.Add(null); } foreach (XmlNode vsUnit in mixer.GetElementsByTagName("vsUnit")) { int vsTrackNo = int.Parse(vsUnit["vsTrackNo"].InnerText); int mute = int.Parse(vsUnit["mute"].InnerText); int solo = int.Parse(vsUnit["solo"].InnerText); int pan = int.Parse(vsUnit["pan"].InnerText); int vol = int.Parse(vsUnit["vol"].InnerText); var slave = new VsqMixerEntry(vol, pan, mute, solo); result.Mixer.Slave[vsTrackNo] = slave; } return(result); }
/// <summary> /// musicalPartを解釈し、パート内の情報をtrackに追加する /// </summary> /// <param name="voiceTable">音源情報のテーブル</param> /// <param name="track">追加先のトラック</param> /// <param name="musicalPart">解釈対象のmusicalPart</param> private static void parseMusicalPart(Dictionary <int, Dictionary <int, IconHandle> > voiceTable, VsqTrack track, XmlNode musicalPart) { int offset = int.Parse(musicalPart["posTick"].InnerText); // 歌手切り替え情報をパース foreach (XmlNode singer in musicalPart.ChildNodes) { if (singer.Name != "singer") { continue; } int posTick = int.Parse(singer["posTick"].InnerText); int bankSelect = int.Parse(singer["vBS"].InnerText); int programChange = int.Parse(singer["vPC"].InnerText); if (voiceTable.ContainsKey(bankSelect) && voiceTable[bankSelect].ContainsKey(programChange)) { var iconHandle = voiceTable[bankSelect][programChange]; var item = new VsqEvent(); item.ID.IconHandle = (IconHandle)iconHandle.clone(); item.ID.type = VsqIDType.Singer; item.Clock = offset + posTick; track.addEvent(item); } else { throw new Exception("音源情報のparseに失敗しました。"); } } // ノート情報をパース foreach (XmlNode note in musicalPart.ChildNodes) { if (note.Name != "note") { continue; } var item = createNoteEvent(note, offset); track.addEvent(item); // OPEカーブを更新 int ope = getOpening(note); var list = track.getCurve("OPE"); list.add(item.Clock, ope); } // OPE以外のコントロールカーブをパース foreach (XmlNode ctrl in musicalPart.ChildNodes) { if (ctrl.Name != "mCtrl") { continue; } int posTick = int.Parse(ctrl["posTick"].InnerText); string id = ctrl["attr"].Attributes["id"].Value; int value = int.Parse(ctrl["attr"].InnerText); var list = track.getCurve(id); if (list != null) { list.add(posTick, value); } } }
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; }
/// <summary> /// 音符の note on/off のためのイベントを作成し、イベントキューに追加する /// </summary> /// <param name="track">生成元のトラック</param> /// <param name="result">生成したイベントの追加先</param> private void appendNoteEvent( VsqTrack track, EventQueueSequence result ) { foreach ( var item in track.MetaText.Events.Events ) { if ( item.ID.type != VsqIDType.Anote ) continue; var note = item.ID.Note; { var clock = item.Clock; var queue = result.get( clock ); var noteOn = driver_.createNoteOnEvent( item.ID.Note, item.ID.Dynamics, item.ID.LyricHandle.L0.Phrase ); queue.noteon.AddRange( noteOn ); } { var clock = item.Clock + item.ID.Length; var queue = result.get( clock ); var noteOff = createNoteOffEvent( clock, item.ID.Note ); queue.noteoff.add( noteOff ); } } }
public void readFromVsqx() { VsqFile vsq = VsqxReader.readFromVsqx("./fixture/track1.vsqx"); // トラック数 Assert.AreEqual(2, vsq.Track.size()); // プリメジャー Assert.AreEqual(4, vsq.getPreMeasure()); // イベント数 // 最初のmusicalPartには歌手変更1個と音符2個 // 2つ目のmusicalPartには歌手変更1個と音符1個が入っているはず VsqTrack track = vsq.Track.get(1); Assert.AreEqual(6, track.getEventCount()); // 歌手変更が正しく読み込まれているか // 1個目はデフォルトの歌手変更なのでスルー var singerChange = track.getEvent(1); Assert.AreEqual(7680, singerChange.Clock); Assert.Null(singerChange.ID.IconDynamicsHandle); Assert.Null(singerChange.ID.LyricHandle); Assert.Null(singerChange.ID.NoteHeadHandle); Assert.Null(singerChange.ID.VibratoHandle); Assert.AreEqual("VY1V3", singerChange.ID.IconHandle.IDS); Assert.AreEqual("$07010000", singerChange.ID.IconHandle.IconID); Assert.AreEqual(0, singerChange.ID.IconHandle.Language); Assert.AreEqual(0, singerChange.ID.IconHandle.Program); // 1つめの音符イベントが正しく読み込まれているか var firstEvent = track.getEvent(2); Assert.AreEqual(7680 + 0, firstEvent.Clock); Assert.AreEqual(48, firstEvent.ID.Note); Assert.AreEqual(480, firstEvent.ID.getLength()); Assert.AreEqual(62, firstEvent.ID.Dynamics); Assert.AreEqual(50, firstEvent.ID.DEMaccent); Assert.AreEqual(8, firstEvent.ID.PMBendDepth); Assert.AreEqual(0, firstEvent.ID.PMBendLength); Assert.AreEqual(50, firstEvent.ID.DEMdecGainRate); Assert.AreEqual(false, firstEvent.ID.isFallPortamento()); Assert.AreEqual(false, firstEvent.ID.isRisePortamento()); Assert.Null(firstEvent.ID.IconDynamicsHandle); Assert.AreEqual("わ", firstEvent.ID.LyricHandle.L0.Phrase); Assert.AreEqual("w a", firstEvent.ID.LyricHandle.L0.getPhoneticSymbol()); Assert.AreEqual(true, firstEvent.ID.LyricHandle.L0.PhoneticSymbolProtected); Assert.Null(firstEvent.ID.NoteHeadHandle); Assert.AreEqual("$04040000", firstEvent.ID.VibratoHandle.IconID); Assert.AreEqual(316, firstEvent.ID.VibratoHandle.getLength()); var depthBP = firstEvent.ID.VibratoHandle.getDepthBP(); Assert.AreEqual(1, depthBP.getCount()); Assert.AreEqual(0.0f, depthBP.getElement(0).X); Assert.AreEqual(64, depthBP.getElement(0).Y); var rateBP = firstEvent.ID.VibratoHandle.getRateBP(); Assert.AreEqual(1, rateBP.getCount()); Assert.AreEqual(0.0f, rateBP.getElement(0).X); Assert.AreEqual(50, rateBP.getElement(0).Y); Assert.AreEqual(164, firstEvent.ID.VibratoDelay); Assert.Null(firstEvent.ID.IconHandle); // 2つめの音符イベントが正しく読み込まれているか var secondEvent = track.getEvent(3); Assert.AreEqual(7680 + 480, secondEvent.Clock); Assert.AreEqual(50, secondEvent.ID.Note); Assert.AreEqual(960, secondEvent.ID.getLength()); Assert.AreEqual(63, secondEvent.ID.Dynamics); Assert.AreEqual(50, secondEvent.ID.DEMaccent); Assert.AreEqual(8, secondEvent.ID.PMBendDepth); Assert.AreEqual(0, secondEvent.ID.PMBendLength); Assert.AreEqual(50, secondEvent.ID.DEMdecGainRate); Assert.AreEqual(true, secondEvent.ID.isFallPortamento()); Assert.AreEqual(false, secondEvent.ID.isRisePortamento()); Assert.Null(secondEvent.ID.IconDynamicsHandle); Assert.AreEqual("は", secondEvent.ID.LyricHandle.L0.Phrase); Assert.AreEqual("h a", secondEvent.ID.LyricHandle.L0.getPhoneticSymbol()); Assert.AreEqual(false, secondEvent.ID.LyricHandle.L0.PhoneticSymbolProtected); Assert.Null(secondEvent.ID.NoteHeadHandle); Assert.AreEqual("$04040004", secondEvent.ID.VibratoHandle.IconID); Assert.AreEqual(624, secondEvent.ID.VibratoHandle.getLength()); depthBP = secondEvent.ID.VibratoHandle.getDepthBP(); Assert.AreEqual(1, depthBP.getCount()); Assert.AreEqual(0.0f, depthBP.getElement(0).X); Assert.AreEqual(64, depthBP.getElement(0).Y); rateBP = secondEvent.ID.VibratoHandle.getRateBP(); Assert.AreEqual(1, secondEvent.ID.VibratoHandle.getRateBP().getCount()); Assert.AreEqual(0.0f, rateBP.getElement(0).X); Assert.AreEqual(64, rateBP.getElement(0).Y); Assert.AreEqual(336, secondEvent.ID.VibratoDelay); Assert.Null(secondEvent.ID.IconHandle); // 2つ目の歌手変更 var singerChange2 = track.getEvent(4); Assert.AreEqual(10560, singerChange2.Clock); Assert.Null(singerChange2.ID.IconDynamicsHandle); Assert.Null(singerChange2.ID.LyricHandle); Assert.Null(singerChange2.ID.NoteHeadHandle); Assert.Null(singerChange2.ID.VibratoHandle); Assert.AreEqual("Miku(V2)", singerChange2.ID.IconHandle.IDS); Assert.AreEqual("$07010001", singerChange2.ID.IconHandle.IconID); Assert.AreEqual(0, singerChange2.ID.IconHandle.Language); Assert.AreEqual(1, singerChange2.ID.IconHandle.Program); // 3つめの音符イベントが正しく読み込まれているか var thirdEvent = track.getEvent(5); Assert.AreEqual(10560 + 665, thirdEvent.Clock); Assert.AreEqual(60, thirdEvent.ID.Note); Assert.AreEqual(480, thirdEvent.ID.getLength()); Assert.AreEqual(64, thirdEvent.ID.Dynamics); Assert.AreEqual(50, thirdEvent.ID.DEMaccent); Assert.AreEqual(8, thirdEvent.ID.PMBendDepth); Assert.AreEqual(0, thirdEvent.ID.PMBendLength); Assert.AreEqual(50, thirdEvent.ID.DEMdecGainRate); Assert.AreEqual(false, thirdEvent.ID.isFallPortamento()); Assert.AreEqual(false, thirdEvent.ID.isRisePortamento()); Assert.Null(thirdEvent.ID.IconDynamicsHandle); Assert.AreEqual("a", thirdEvent.ID.LyricHandle.L0.Phrase); Assert.AreEqual("a", thirdEvent.ID.LyricHandle.L0.getPhoneticSymbol()); Assert.AreEqual(false, thirdEvent.ID.LyricHandle.L0.PhoneticSymbolProtected); Assert.Null(thirdEvent.ID.NoteHeadHandle); Assert.AreEqual("$04040000", thirdEvent.ID.VibratoHandle.IconID); Assert.AreEqual(316, thirdEvent.ID.VibratoHandle.getLength()); depthBP = thirdEvent.ID.VibratoHandle.getDepthBP(); Assert.AreEqual(1, depthBP.getCount()); Assert.AreEqual(0.0f, depthBP.getElement(0).X); Assert.AreEqual(64, depthBP.getElement(0).Y); rateBP = thirdEvent.ID.VibratoHandle.getRateBP(); Assert.AreEqual(1, thirdEvent.ID.VibratoHandle.getRateBP().getCount()); Assert.AreEqual(0.0f, rateBP.getElement(0).X); Assert.AreEqual(50, rateBP.getElement(0).Y); Assert.AreEqual(164, thirdEvent.ID.VibratoDelay); Assert.Null(thirdEvent.ID.IconHandle); // トラック名 Assert.AreEqual("Track", track.getName()); // テンポ変更 Assert.AreEqual(2, vsq.TempoTable.size()); Assert.AreEqual(0, vsq.TempoTable.get(0).Clock); Assert.AreEqual(500000, vsq.TempoTable.get(0).Tempo); Assert.AreEqual(8640, vsq.TempoTable.get(1).Clock); Assert.AreEqual(1199760, vsq.TempoTable.get(1).Tempo); // 拍子変更 Assert.AreEqual(2, vsq.TimesigTable.size()); Assert.AreEqual(0, vsq.TimesigTable.get(0).Clock); Assert.AreEqual(4, vsq.TimesigTable.get(0).Numerator); Assert.AreEqual(4, vsq.TimesigTable.get(0).Denominator); Assert.AreEqual(9600, vsq.TimesigTable.get(1).Clock); Assert.AreEqual(3, vsq.TimesigTable.get(1).Numerator); Assert.AreEqual(4, vsq.TimesigTable.get(1).Denominator); // コントロールカーブ // DYN var dyn = track.getCurve("DYN"); Assert.AreEqual(1, dyn.size()); Assert.AreEqual(720, dyn.getKeyClock(0)); Assert.AreEqual(96, dyn.getElement(0)); // BRE var bre = track.getCurve("BRE"); Assert.AreEqual(1, bre.size()); Assert.AreEqual(720, bre.getKeyClock(0)); Assert.AreEqual(102, bre.getElement(0)); // BRI // CLE // OPE var ope = track.getCurve("OPE"); Assert.AreEqual(3, ope.size()); Assert.AreEqual(7680 + 0, ope.getKeyClock(0)); Assert.AreEqual(127, ope.getElement(0)); Assert.AreEqual(7680 + 480, ope.getKeyClock(1)); Assert.AreEqual(127, ope.getElement(1)); Assert.AreEqual(10560 + 665, ope.getKeyClock(2)); Assert.AreEqual(127, ope.getElement(2)); // GEN // POR // PIT // PBS // Mixerが正しく読み込まれているか Assert.AreEqual(2, vsq.Mixer.MasterFeder); Assert.AreEqual(1, vsq.Mixer.Slave.size()); Assert.AreEqual(1, vsq.Mixer.Slave.get(0).Solo); Assert.AreEqual(0, vsq.Mixer.Slave.get(0).Mute); Assert.AreEqual(64, vsq.Mixer.Slave.get(0).Panpot); Assert.AreEqual(1, vsq.Mixer.Slave.get(0).Feder); }
/// <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); }
public bool edit( VsqTrack track, int[] event_internal_ids, MouseButtons button ) { bool edited = false; try { int divide_threshold = Numerator * 480 * 4 / Denominator; Console.WriteLine( "s_divide_threshold=" + divide_threshold ); Keys modifier = Control.ModifierKeys; bool middle_mode = button == MouseButtons.Middle; if ( getModifier().Equals( "Alt" ) ) { if ( (modifier & Keys.Alt) == Keys.Alt ) { middle_mode = true; } } else if ( getModifier().Equals( "Control" ) ) { if ( (modifier & Keys.Control) == Keys.Control ) { middle_mode = true; } } else if ( getModifier().Equals( "Shift" ) ) { if ( (modifier & Keys.Shift) == Keys.Shift ) { middle_mode = true; } } Console.WriteLine( "DivideNote#edit; (event_internal_ids==null)=" + (event_internal_ids == null) ); foreach ( int id in event_internal_ids ) { Console.WriteLine( "DivideNote#edit; (track==null)=" + (track == null) ); for ( Iterator<VsqEvent> itr = track.getNoteEventIterator(); itr.hasNext(); ) { VsqEvent ve = itr.next(); Console.WriteLine( "DivideNote#edit; (ve==null)=" + (ve == null) ); if ( ve.InternalID == id ) { Console.WriteLine( "DivideNote#edit; (ve.ID==null)=" + (ve.ID == null) ); if ( ve.ID.Length >= divide_threshold * 2 ) { Console.WriteLine( "before; clock=" + ve.Clock + "; length=" + ve.ID.Length ); VsqEvent add = (VsqEvent)ve.clone(); int length = ve.ID.Length; List<string> symbol = ve.ID.LyricHandle.L0.getPhoneticSymbolList(); for ( int i = 0; i < symbol.Count; i++ ) { Console.WriteLine( "symbol[" + i + "]=" + symbol[i] ); } ve.ID.Length = divide_threshold; add.Clock = ve.Clock + divide_threshold; add.ID.Length = length - divide_threshold; if ( add.ID.VibratoHandle != null ) { if ( add.ID.VibratoDelay >= add.ID.Length ) { add.ID.VibratoHandle = null; } } if ( ve.ID.VibratoHandle != null ) { if ( ve.ID.VibratoDelay >= ve.ID.Length ) { ve.ID.VibratoHandle = null; } } if ( symbol.Count >= 2 ) { if ( middle_mode && !VsqPhoneticSymbol.isConsonant( symbol[1] ) ) { ve.ID.LyricHandle.L0.setPhoneticSymbol( symbol[0] + " " + symbol[1] ); } else { ve.ID.LyricHandle.L0.setPhoneticSymbol( symbol[0] ); } string symbol2 = ""; for ( int i = 1; i < symbol.Count; i++ ) { symbol2 += ((i == 1) ? "" : " ") + symbol[i]; } Console.WriteLine( "symbol2=" + symbol2 ); add.ID.LyricHandle.L0.setPhoneticSymbol( symbol2 ); } track.addEvent( add ); edited = true; } break; } } } } catch ( Exception ex ) { Console.WriteLine( "DivideNote#edit; ex=" + ex ); } return edited; }
public void patchWork(WorkerState state, Object arg) { #if DEBUG sout.println("SynthesizeWorker#patchWork"); #endif VsqFileEx vsq = AppManager.getVsqFile(); Object[] args = (Object[])arg; List <PatchWorkQueue> queue = (List <PatchWorkQueue>)args[0]; List <int> tracks = (List <int>)args[1]; int finished = queue.Count; string temppath = AppManager.getTempWaveDir(); for (int k = 0; k < tracks.Count; k++) { int track = tracks[k]; string wavePath = Path.Combine(temppath, track + ".wav"); List <int> queueIndex = new List <int>(); for (int i = 0; i < queue.Count; i++) { if (queue[i].track == track) { queueIndex.Add(i); } } if (queueIndex.Count <= 0) { // 第trackトラックに対してパッチワークを行う必要無し continue; } #if DEBUG sout.println("AppManager#pathWorkToFreeze; wavePath=" + wavePath + "; queue.get( queueIndex.get( 0 ) ).file=" + queue[queueIndex[0]].file); sout.println("AppManager#pathWorkToFreeze; queueIndex.size()=" + queueIndex.Count); #endif if (queueIndex.Count == 1 && wavePath.Equals(queue[queueIndex[0]].file)) { // 第trackトラック全体の合成を指示するキューだった場合. // このとき,パッチワークを行う必要なし. AppManager.mLastRenderedStatus[track - 1] = new RenderedStatus((VsqTrack)vsq.Track[track].clone(), vsq.TempoTable, (SequenceConfig)vsq.config.clone()); AppManager.serializeRenderingStatus(temppath, track); AppManager.invokeWaveViewReloadRequiredEvent(track, wavePath, 1, -1); continue; } WaveWriter writer = null; try { int sampleRate = vsq.config.SamplingRate; long totalLength = (long)((vsq.getSecFromClock(vsq.TotalClocks) + 1.0) * sampleRate); writer = new WaveWriter(wavePath, vsq.config.WaveFileOutputChannel, 16, sampleRate); int BUFLEN = 1024; double[] bufl = new double[BUFLEN]; double[] bufr = new double[BUFLEN]; double total = 0.0; for (int m = 0; m < queueIndex.Count; m++) { int i = queueIndex[m]; if (finished <= i) { break; } // パッチワークの開始秒時 double secStart = vsq.getSecFromClock(queue[i].clockStart); long sampleStart = (long)(secStart * sampleRate); // パッチワークの終了秒時 int clockEnd = queue[i].clockEnd; if (clockEnd == int.MaxValue) { clockEnd = vsq.TotalClocks + 240; } double secEnd = vsq.getSecFromClock(clockEnd); long sampleEnd = (long)(secEnd * sampleRate); WaveReader wr = null; try { wr = new WaveReader(queue[i].file); long remain2 = sampleEnd - sampleStart; long proc = 0; while (remain2 > 0) { int delta = remain2 > BUFLEN ? BUFLEN : (int)remain2; wr.read(proc, delta, bufl, bufr); writer.replace(sampleStart + proc, delta, bufl, bufr); proc += delta; remain2 -= delta; total += delta; state.reportProgress(total); } } catch (Exception ex) { Logger.write(typeof(AppManager) + ".patchWorkToFreeze; ex=" + ex + "\n"); serr.println("AppManager#patchWorkToFreeze; ex=" + ex); } finally { if (wr != null) { try { wr.close(); } catch (Exception ex2) { Logger.write(typeof(AppManager) + ".patchWorkToFreeze; ex=" + ex2 + "\n"); serr.println("AppManager#patchWorkToFreeze; ex2=" + ex2); } } } try { PortUtil.deleteFile(queue[i].file); } catch (Exception ex) { Logger.write(typeof(AppManager) + ".patchWorkToFreeze; ex=" + ex + "\n"); serr.println("AppManager#patchWorkToFreeze; ex=" + ex); } } VsqTrack vsq_track = vsq.Track[track]; if (queueIndex[queueIndex.Count - 1] <= finished) { // 途中で終了せず,このトラックの全てのパッチワークが完了した. AppManager.mLastRenderedStatus[track - 1] = new RenderedStatus((VsqTrack)vsq_track.clone(), vsq.TempoTable, (SequenceConfig)vsq.config.clone()); AppManager.serializeRenderingStatus(temppath, track); AppManager.setRenderRequired(track, false); } else { // パッチワークの作成途中で,キャンセルされた // キャンセルされたやつ以降の範囲に、プログラムチェンジ17の歌手変更イベントを挿入する。→AppManager#detectTrackDifferenceに必ず検出してもらえる。 VsqTrack copied = (VsqTrack)vsq_track.clone(); VsqEvent dumy = new VsqEvent(); dumy.ID.type = VsqIDType.Singer; dumy.ID.IconHandle = new IconHandle(); dumy.ID.IconHandle.Program = 17; for (int m = 0; m < queueIndex.Count; m++) { int i = queueIndex[m]; if (i < finished) { continue; } int start = queue[i].clockStart; int end = queue[i].clockEnd; VsqEvent singerAtEnd = vsq_track.getSingerEventAt(end); // startの位置に歌手変更が既に指定されていないかどうかを検査 int foundStart = -1; int foundEnd = -1; for (Iterator <int> itr = copied.indexIterator(IndexIteratorKind.SINGER); itr.hasNext();) { int j = itr.next(); VsqEvent ve = copied.getEvent(j); if (ve.Clock == start) { foundStart = j; } if (ve.Clock == end) { foundEnd = j; } if (end < ve.Clock) { break; } } VsqEvent dumyStart = (VsqEvent)dumy.clone(); dumyStart.Clock = start; if (foundStart >= 0) { copied.setEvent(foundStart, dumyStart); } else { copied.addEvent(dumyStart); } if (end != int.MaxValue) { VsqEvent dumyEnd = (VsqEvent)singerAtEnd.clone(); dumyEnd.Clock = end; if (foundEnd >= 0) { copied.setEvent(foundEnd, dumyEnd); } else { copied.addEvent(dumyEnd); } } copied.sortEvent(); } AppManager.mLastRenderedStatus[track - 1] = new RenderedStatus(copied, vsq.TempoTable, (SequenceConfig)vsq.config.clone()); AppManager.serializeRenderingStatus(temppath, track); } state.reportComplete(); } catch (Exception ex) { Logger.write(typeof(AppManager) + ".patchWorkToFreeze; ex=" + ex + "\n"); serr.println("AppManager#patchWorkToFreeze; ex=" + ex); } finally { if (writer != null) { try { writer.close(); } catch (Exception ex2) { Logger.write(typeof(AppManager) + ".patchWorkToFreeze; ex=" + ex2 + "\n"); serr.println("AppManager#patchWorkToFreeze; ex2=" + ex2); } } } // 波形表示用のWaveDrawContextの内容を更新する。 /*for ( int j = 0; j < queueIndex.size(); j++ ) { * int i = queueIndex.get( j ); * if ( i >= finished ) { * continue; * } * double secStart = mVsq.getSecFromClock( queue.get( i ).clockStart ); * int clockEnd = queue.get( i ).clockEnd; * if ( clockEnd == int.MaxValue ) { * clockEnd = mVsq.TotalClocks + 240; * } * double secEnd = mVsq.getSecFromClock( clockEnd ); * * invokeWaveViewReloadRequiredEvent( tracks.get( k ), wavePath, secStart, secEnd ); * }*/ AppManager.invokeWaveViewReloadRequiredEvent(track, wavePath, 1, -1); } #if DEBUG sout.println("SynthesizeWorker#patchWork; done"); #endif state.reportComplete(); }
public RenderedStatus() { track = new VsqTrack(0, 0, 0); tempo = new TempoVector(); config = new SequenceConfig(); }
public void begin(long total_samples, WorkerState state) { var mDriver = getDriver(); #if DEBUG sout.println("AquesToneRenderingRunner#begin; (mDriver==null)=" + (mDriver == null)); String file = System.IO.Path.Combine(System.Windows.Forms.Application.StartupPath, "AquesToneWaveGenerator.txt"); log = new System.IO.StreamWriter(file); log.AutoFlush = true; #endif if (mDriver == null) { #if DEBUG log.WriteLine("mDriver==null"); log.Close(); #endif exitBegin(); state.reportComplete(); return; } #if DEBUG sout.println("AquesToneRenderingRunner#begin; mDriver.loaded=" + mDriver.loaded); #endif if (!mDriver.loaded) { #if DEBUG log.WriteLine("mDriver.loaded=" + mDriver.loaded); log.Close(); #endif exitBegin(); state.reportComplete(); return; } mRunning = true; //mAbortRequired = false; mTotalSamples = total_samples; #if DEBUG sout.println("AquesToneWaveGenerator#begin; mTotalSamples=" + mTotalSamples); log.WriteLine("mTotalSamples=" + mTotalSamples); log.WriteLine("mTrimRemain=" + mTrimRemain); #endif VsqTrack track = mVsq.Track.get(mTrack); int BUFLEN = mSampleRate / 10; double[] left = new double[BUFLEN]; double[] right = new double[BUFLEN]; long saProcessed = 0; int saRemain = 0; int lastClock = 0; // 最後に処理されたゲートタイム // 最初にダミーの音を鳴らす // (最初に入るノイズを回避するためと、前回途中で再生停止した場合に無音から始まるようにするため) mDriver.resetAllParameters(); mDriver.process(left, right, BUFLEN); MidiEvent f_noteon = new MidiEvent(); f_noteon.firstByte = 0x90; f_noteon.data = new int[] { 0x40, 0x40 }; f_noteon.clock = 0; mDriver.send(new MidiEvent[] { f_noteon }); mDriver.process(left, right, BUFLEN); MidiEvent f_noteoff = new MidiEvent(); f_noteoff.firstByte = 0x80; f_noteoff.data = new int[] { 0x40, 0x7F }; mDriver.send(new MidiEvent[] { f_noteoff }); for (int i = 0; i < 3; i++) { mDriver.process(left, right, BUFLEN); } #if DEBUG log.WriteLine("pre-process done"); log.WriteLine("-----------------------------------------------------"); VsqTrack vsq_track = mVsq.Track.get(mTrack); for (Iterator <VsqEvent> itr = vsq_track.getNoteEventIterator(); itr.hasNext();) { VsqEvent item = itr.next(); log.WriteLine("c" + item.Clock + "; " + item.ID.LyricHandle.L0.Phrase); } #endif // レンダリング開始位置での、パラメータの値をセットしておく for (Iterator <VsqEvent> itr = track.getNoteEventIterator(); itr.hasNext();) { VsqEvent item = itr.next(); #if DEBUG sout.println("AquesToneWaveGenerator#begin; item.Clock=" + item.Clock); log.WriteLine("*********************************************************"); log.WriteLine("item.Clock=" + item.Clock); #endif long saNoteStart = (long)(mVsq.getSecFromClock(item.Clock) * mSampleRate); long saNoteEnd = (long)(mVsq.getSecFromClock(item.Clock + item.ID.getLength()) * mSampleRate); #if DEBUG log.WriteLine("saNoteStart=" + saNoteStart + "; saNoteEnd=" + saNoteEnd); #endif EventQueueSequence list = generateMidiEvent(mVsq, mTrack, lastClock, item.Clock + item.ID.getLength()); lastClock = item.Clock + item.ID.Length + 1; for (Iterator <Integer> itr2 = list.keyIterator(); itr2.hasNext();) { // まず直前までの分を合成 Integer clock = itr2.next(); #if DEBUG log.WriteLine("-------------------------------------------------------"); sout.println("AquesToneWaveGenerator#begin; clock=" + clock); #endif long saStart = (long)(mVsq.getSecFromClock(clock) * mSampleRate); saRemain = (int)(saStart - saProcessed); #if DEBUG log.WriteLine("saStart=" + saStart); log.WriteLine("saRemain=" + saRemain); #endif while (saRemain > 0) { if (state.isCancelRequested()) { goto heaven; } int len = saRemain > BUFLEN ? BUFLEN : saRemain; mDriver.process(left, right, len); waveIncoming(left, right, len); saRemain -= len; saProcessed += len; state.reportProgress(saProcessed); //mTotalAppend += len; <- waveIncomingで計算されるので } // MIDiイベントを送信 MidiEventQueue queue = list.get(clock); // まずnoteoff boolean noteoff_send = false; if (queue.noteoff.size() > 0) { #if DEBUG for (int i = 0; i < queue.noteoff.size(); i++) { String str = ""; MidiEvent itemi = queue.noteoff.get(i); str += "0x" + PortUtil.toHexString(itemi.firstByte, 2) + " "; for (int j = 0; j < itemi.data.Length; j++) { str += "0x" + PortUtil.toHexString(itemi.data[j], 2) + " "; } sout.println(typeof(AquesToneWaveGenerator) + "#begin; noteoff; " + str); } #endif mDriver.send(queue.noteoff.toArray(new MidiEvent[] { })); noteoff_send = true; } // parameterの変更 if (queue.param.size() > 0) { for (Iterator <ParameterEvent> itr3 = queue.param.iterator(); itr3.hasNext();) { ParameterEvent pe = itr3.next(); #if DEBUG sout.println(typeof(AquesToneWaveGenerator) + "#begin; param; index=" + pe.index + "; value=" + pe.value); #endif mDriver.setParameter(pe.index, pe.value); } } // ついでnoteon if (queue.noteon.size() > 0) { // 同ゲートタイムにピッチベンドも指定されている場合、同時に送信しないと反映されないようだ! if (queue.pit.size() > 0) { queue.noteon.addAll(queue.pit); queue.pit.clear(); } #if DEBUG for (int i = 0; i < queue.noteon.size(); i++) { String str = ""; MidiEvent itemi = queue.noteon.get(i); str += "0x" + PortUtil.toHexString(itemi.firstByte, 2) + " "; for (int j = 0; j < itemi.data.Length; j++) { str += "0x" + PortUtil.toHexString(itemi.data[j], 2) + " "; } sout.println(typeof(AquesToneWaveGenerator) + "#begin; noteon; " + str); } #endif mDriver.send(queue.noteon.toArray(new MidiEvent[] { })); } // PIT if (queue.pit.size() > 0 && !noteoff_send) { #if DEBUG for (int i = 0; i < queue.pit.size(); i++) { String str = ""; MidiEvent itemi = queue.pit.get(i); str += "0x" + PortUtil.toHexString(itemi.firstByte, 2) + " "; for (int j = 0; j < itemi.data.Length; j++) { str += "0x" + PortUtil.toHexString(itemi.data[j], 2) + " "; } sout.println(typeof(AquesToneWaveGenerator) + "#begin; pit; " + str); } #endif mDriver.send(queue.pit.toArray(new MidiEvent[] { })); } if (mDriver.getUi(mMainWindow) != null) { mDriver.getUi(mMainWindow).invalidateUi(); } } } // totalSamplesに足りなかったら、追加してレンダリング saRemain = (int)(mTotalSamples - mTotalAppend); #if DEBUG sout.println("AquesToneRenderingRunner#run; totalSamples=" + mTotalSamples + "; mTotalAppend=" + mTotalAppend + "; saRemain=" + saRemain); #endif while (saRemain > 0) { if (state.isCancelRequested()) { goto heaven; } int len = saRemain > BUFLEN ? BUFLEN : saRemain; mDriver.process(left, right, len); waveIncoming(left, right, len); saRemain -= len; saProcessed += len; state.reportProgress(saProcessed); //mTotalAppend += len; } heaven: #if DEBUG log.Close(); #endif exitBegin(); state.reportComplete(); }
/// <summary> /// Create MusicXML.scorepartwisePart object by VsqTrack instance. /// </summary> /// <param name="track"></param> /// <param name="timesig_table"></param> /// <returns></returns> private scorepartwisePart createScorePart(VsqTrack track, TimesigVector timesig_table, TempoVector tempo_table) { var part = new scorepartwisePart(); var note_list = quantizeTrack(track, timesig_table, tempo_table); var measures = new List <scorepartwisePartMeasure>(); int measure = 0; Timesig timesig = new Timesig(0, 0); while (0 < note_list.Count) { int measure_start_clock = timesig_table.getClockFromBarCount(measure); int measure_end_clock = timesig_table.getClockFromBarCount(measure + 1); var tempo_change_in_measure = new TempoVector(); tempo_change_in_measure.AddRange( tempo_table .Where((tempo) => measure_start_clock <= tempo.Clock && tempo.Clock < measure_end_clock) .Select((tempo) => (TempoTableEntry)tempo.Clone())); // get the list of TiedEvent, contained in target measure. var in_measure_tied_note_list = note_list .Where((tied_event) => { int tied_event_start = tied_event.Clock; int tied_event_end = tied_event.Clock + tied_event.Length; return ((measure_start_clock <= tied_event_start && tied_event_start < measure_end_clock) || (measure_start_clock <= tied_event_end && tied_event_end < measure_end_clock) || (tied_event_start <= measure_start_clock && measure_end_clock <= tied_event_end)); }); // get the list of MusicXML.note. var in_measure_note_list = in_measure_tied_note_list .SelectMany((tied_event) => { var result = new List <object>(); int clock = tied_event.Clock; foreach (var note in tied_event) { int length = (int)note.duration.First; if (measure_start_clock <= clock && clock + length <= measure_end_clock) { var tempo_change = tempo_change_in_measure .FirstOrDefault((tempo) => tempo.Clock == clock); if (tempo_change != null) { var direction = new direction(); direction.placement = abovebelow.above; direction.placementSpecified = true; direction.directiontype = new directiontype[] { new directiontype() }; direction.directiontype[0].metronome.Add(new metronome()); var perminute = new perminute(); perminute.Value = getTempo(tempo_change).ToString(); direction.directiontype[0].metronome[0].Items = new object[] { notetypevalue.quarter, perminute }; direction.sound = new sound(); direction.sound.tempo = getTempo(tempo_change); direction.sound.tempoSpecified = true; result.Add(direction); } result.Add(note); } clock += length; } return(result); }); var partwise_measure = new scorepartwisePartMeasure(); partwise_measure.number = (measure + 1).ToString(); var items = new List <object>(); var measure_timesig = timesig_table.getTimesigAt(measure_start_clock); if (!measure_timesig.Equals(timesig)) { var attributes = new MusicXML.attributes(); attributes.divisions = 480; attributes.divisionsSpecified = true; attributes.time = new time[] { new time() }; attributes.time[0].beats.Add(measure_timesig.numerator.ToString()); attributes.time[0].beattype.Add(measure_timesig.denominator.ToString()); attributes.time[0].symbol = timesymbol.common; attributes.time[0].symbolSpecified = true; items.Add(attributes); } timesig = measure_timesig; items.AddRange(in_measure_note_list); partwise_measure.Items = items.ToArray(); measures.Add(partwise_measure); note_list.RemoveAll((tied_event) => tied_event.Clock + tied_event.Length <= measure_end_clock); measure++; } part.measure = measures.ToArray(); return(part); }
/// <summary> /// ピッチとピッチベンドセンシティビティをイベントキューに追加する /// </summary> /// <param name="track"></param> /// <param name="sequence"></param> private void appendPitchEvent( VsqTrack track, EventQueueSequence sequence ) { // 実際に AquesTone2 に送信する pbs の値と、pbs カーブに入っている値とのマップ const int maxPitchBendSensitivity = 23; int[] map = new int[maxPitchBendSensitivity + 1] { 0, 5, 15, 35, 44, 54, 64, 74, 84, 93, 103, 113, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, }; var pbs = track.MetaText.PBS; for ( int i = 0; i < pbs.size(); ++i ) { var clock = pbs.getKeyClock( i ); { // RPN MSB = 0x00 var e = new MidiEvent(); e.firstByte = 0xB0; e.data = new int[] { 0x65, 0x00 }; e.clock = clock; sequence.get( clock ).pit.add( e ); } { // RPN LSB = 0x00 var e = new MidiEvent(); e.firstByte = 0xB0; e.data = new int[] { 0x64, 0x00 }; e.clock = clock; sequence.get( clock ).pit.add( e ); } { // RPN data MSB var e = new MidiEvent(); e.firstByte = 0xB0; int value = Math.Max( 0, Math.Min( maxPitchBendSensitivity, pbs.getElementA( i ) ) ); e.data = new int[] { 0x06, map[value] }; e.clock = clock; sequence.get( clock ).pit.add( e ); } } var pit = track.MetaText.PIT; for ( int i = 0; i < pit.size(); ++i ) { var clock = pit.getKeyClock( i ); var e = new MidiEvent(); e.firstByte = 0xE0; var value = pit.getElementA( i ) + 8192; var msb = 0x7F & value; var lsb = 0x7F & (value >> 7); e.data = new int[] { msb, lsb }; sequence.get( clock ).pit.add( e ); } }
public bool edit(VsqTrack track, int[] event_internal_ids, MouseButtons button) { bool edited = false; try { int divide_threshold = Numerator * 480 * 4 / Denominator; Console.WriteLine("s_divide_threshold=" + divide_threshold); Keys modifier = Control.ModifierKeys; bool middle_mode = button == MouseButtons.Middle; if (getModifier().Equals("Alt")) { if ((modifier & Keys.Alt) == Keys.Alt) { middle_mode = true; } } else if (getModifier().Equals("Control")) { if ((modifier & Keys.Control) == Keys.Control) { middle_mode = true; } } else if (getModifier().Equals("Shift")) { if ((modifier & Keys.Shift) == Keys.Shift) { middle_mode = true; } } Console.WriteLine("DivideNote#edit; (event_internal_ids==null)=" + (event_internal_ids == null)); foreach (int id in event_internal_ids) { Console.WriteLine("DivideNote#edit; (track==null)=" + (track == null)); foreach (var ve in track.getNoteEventIterator()) { Console.WriteLine("DivideNote#edit; (ve==null)=" + (ve == null)); if (ve.InternalID == id) { Console.WriteLine("DivideNote#edit; (ve.ID==null)=" + (ve.ID == null)); if (ve.ID.Length >= divide_threshold * 2) { Console.WriteLine("before; clock=" + ve.Clock + "; length=" + ve.ID.Length); VsqEvent add = (VsqEvent)ve.clone(); int length = ve.ID.Length; List <string> symbol = ve.ID.LyricHandle.L0.getPhoneticSymbolList(); for (int i = 0; i < symbol.Count; i++) { Console.WriteLine("symbol[" + i + "]=" + symbol[i]); } ve.ID.Length = divide_threshold; add.Clock = ve.Clock + divide_threshold; add.ID.Length = length - divide_threshold; if (add.ID.VibratoHandle != null) { if (add.ID.VibratoDelay >= add.ID.Length) { add.ID.VibratoHandle = null; } } if (ve.ID.VibratoHandle != null) { if (ve.ID.VibratoDelay >= ve.ID.Length) { ve.ID.VibratoHandle = null; } } if (symbol.Count >= 2) { if (middle_mode && !VsqPhoneticSymbol.isConsonant(symbol[1])) { ve.ID.LyricHandle.L0.setPhoneticSymbol(symbol[0] + " " + symbol[1]); } else { ve.ID.LyricHandle.L0.setPhoneticSymbol(symbol[0]); } string symbol2 = ""; for (int i = 1; i < symbol.Count; i++) { symbol2 += ((i == 1) ? "" : " ") + symbol[i]; } Console.WriteLine("symbol2=" + symbol2); add.ID.LyricHandle.L0.setPhoneticSymbol(symbol2); } track.addEvent(add); edited = true; } break; } } } } catch (Exception ex) { Console.WriteLine("DivideNote#edit; ex=" + ex); } return(edited); }
public void processQueue(WorkerState state, Object arg) { #if DEBUG sout.println("SynthesizeWorker#processQueue"); #endif PatchWorkQueue q = (PatchWorkQueue)arg; VsqFileEx vsq = q.vsq; int channel = vsq.config.WaveFileOutputChannel == 1 ? 1 : 2; double amp_master = VocaloSysUtil.getAmplifyCoeffFromFeder(vsq.Mixer.MasterFeder); double pan_left_master = VocaloSysUtil.getAmplifyCoeffFromPanLeft(vsq.Mixer.MasterPanpot); double pan_right_master = VocaloSysUtil.getAmplifyCoeffFromPanRight(vsq.Mixer.MasterPanpot); int numTrack = vsq.Track.Count; string tmppath = AppManager.getTempWaveDir(); int track = q.track; VsqTrack vsq_track = vsq.Track[track]; int count = vsq_track.getEventCount(); if (count <= 0) { return;// false; } double amp_track = VocaloSysUtil.getAmplifyCoeffFromFeder(vsq.Mixer.Slave[track - 1].Feder); double pan_left_track = VocaloSysUtil.getAmplifyCoeffFromPanLeft(vsq.Mixer.Slave[track - 1].Panpot); double pan_right_track = VocaloSysUtil.getAmplifyCoeffFromPanRight(vsq.Mixer.Slave[track - 1].Panpot); double amp_left = amp_track * pan_left_track; double amp_right = amp_track * pan_right_track; int total_clocks = vsq.TotalClocks; double total_sec = vsq.getSecFromClock(total_clocks); RendererKind kind = VsqFileEx.getTrackRendererKind(vsq_track); mGenerator = VSTiDllManager.getWaveGenerator(kind); Amplifier amp = new Amplifier(); amp.setRoot(mGenerator); if (q.renderAll) { amp.setAmplify(amp_left, amp_right); } mGenerator.setReceiver(amp); mGenerator.setGlobalConfig(AppManager.editorConfig); mGenerator.setMainWindow(mMainWindow); Mixer mixer = new Mixer(); mixer.setRoot(mGenerator); mixer.setGlobalConfig(AppManager.editorConfig); amp.setReceiver(mixer); if (q.renderAll && vsq.config.WaveFileOutputFromMasterTrack) { // トラック全体を合成するモードで,かつ,他トラックを合成して出力するよう指示された場合 if (numTrack > 2) { for (int i = 1; i < numTrack; i++) { if (i == track) { continue; } string file = Path.Combine(tmppath, i + ".wav"); if (!File.Exists(file)) { // mixするべきファイルが揃っていないのでbailout return;// true; } WaveReader r = null; try { r = new WaveReader(file); } catch (Exception ex) { Logger.write(typeof(SynthesizeWorker) + ".processQueue; ex=" + ex + "\n"); r = null; } if (r == null) { return;// true; } double end_sec = vsq.getSecFromClock(q.clockStart); r.setOffsetSeconds(end_sec); Amplifier amp_i_unit = new Amplifier(); amp_i_unit.setRoot(mGenerator); double amp_i = VocaloSysUtil.getAmplifyCoeffFromFeder(vsq.Mixer.Slave[i - 1].Feder); double pan_left_i = VocaloSysUtil.getAmplifyCoeffFromPanLeft(vsq.Mixer.Slave[i - 1].Panpot); double pan_right_i = VocaloSysUtil.getAmplifyCoeffFromPanRight(vsq.Mixer.Slave[i - 1].Panpot); double amp_left_i = amp_i * pan_left_i; double amp_right_i = amp_i * pan_right_i; #if DEBUG sout.println("FormSynthesize#bgWork_DoWork; #" + i + "; amp_left_i=" + amp_left_i + "; amp_right_i=" + amp_right_i); #endif amp_i_unit.setAmplify(amp_left_i, amp_right_i); FileWaveSender wave_sender = new FileWaveSender(r); wave_sender.setRoot(mGenerator); wave_sender.setGlobalConfig(AppManager.editorConfig); amp_i_unit.setSender(wave_sender); mixer.addSender(amp_i_unit); } } } PortUtil.deleteFile(q.file); int sample_rate = vsq.config.SamplingRate; #if DEBUG sout.println("FormSynthesize#bgWork_DoWork; q.file=" + q.file); #endif FileWaveReceiver wave_receiver = new FileWaveReceiver(q.file, channel, 16, sample_rate); wave_receiver.setRoot(mGenerator); wave_receiver.setGlobalConfig(AppManager.editorConfig); Amplifier amp_unit_master = new Amplifier(); amp_unit_master.setRoot(mGenerator); if (q.renderAll) { double l = amp_master * pan_left_master; double r = amp_master * pan_right_master; amp_unit_master.setAmplify(l, r); } mixer.setReceiver(amp_unit_master); amp_unit_master.setReceiver(wave_receiver); int end = q.clockEnd; if (end == int.MaxValue) { end = vsq.TotalClocks + 240; } mGenerator.init(vsq, track, q.clockStart, end, sample_rate); double sec_start = vsq.getSecFromClock(q.clockStart); double sec_end = vsq.getSecFromClock(end); long samples = (long)((sec_end - sec_start) * sample_rate); mGenerator.begin(samples, state); return;// false; }