/// <summary> /// vsqファイルのstart_clockクロックからメトロノームを起動する。startは、start_clockをいつから起動したかを指定する。 /// </summary> /// <param name="vsq"></param> /// <param name="start_clock"></param> /// <param name="start"></param> public static void Start(VsqFileEx vsq, int start_clock, double start_time) { s_queue.clear(); m_stop_required = false; m_stop_metronome_required = false; if (s_device0 == null) { s_device0 = new MidiDeviceImp(s_metronome_device); } if (s_metronome_device != s_general_device) { if (s_device1 == null) { s_device1 = new MidiDeviceImp(s_general_device); } } m_vsq = (VsqFileEx)vsq.clone(); m_started_sec = m_vsq.getSecFromClock(start_clock); ByRef <Integer> bar = new ByRef <Integer>(); Timesig timesig = m_vsq.getTimesigAt(start_clock, bar); int clock_at_bartop = m_vsq.getClockFromBarCount(bar.value); int clock_step = 480 * 4 / timesig.denominator; int next_clock = clock_at_bartop + ((start_clock - clock_at_bartop) / clock_step + 1) * clock_step; m_started = start_time; m_started_clock = start_clock; m_temp_exit = false; for (int track = 1; track < m_vsq.Track.size(); track++) { #if DEBUG AppManager.debugWriteLine("Metronome.Start; track=" + track); #endif for (Iterator <VsqEvent> itr = m_vsq.Track.get(track).getNoteEventIterator(); itr.hasNext();) { VsqEvent item = itr.next(); if (start_clock <= item.Clock) { MidiQueue q = new MidiQueue(); q.Track = track; q.Channel = (byte)(track - 1); q.Clock = item.Clock; q.Note = (byte)(item.ID.Note); q.Program = 0; q.Velocity = 0x40; q.Done += new MidiQueueDoneEventHandler(ReGenerateMidiQueue); s_queue.add(q); break; } } } Collections.sort(s_queue); m_thread = new Thread(new ThreadStart(ThreadProc)); m_thread.IsBackground = true; m_thread.Priority = ThreadPriority.Highest; m_thread.Start(); }
public void handleCommonMouseDown(Object sender, MouseEventArgs e) { if (AppManager.getEditMode() != EditMode.NONE) { return; } DraggableBButton btn = (DraggableBButton)sender; if (mMainWindow != null) { mMainWindow.BringToFront(); } IconDynamicsHandle handle = btn.getHandle(); VsqEvent item = new VsqEvent(); item.Clock = 0; item.ID.Note = 60; item.ID.type = VsqIDType.Aicon; item.ID.IconDynamicsHandle = (IconDynamicsHandle)handle.clone(); int length = handle.getLength(); if (length <= 0) { length = 1; } item.ID.setLength(length); AppManager.mAddingEvent = item; btn.DoDragDrop(handle, System.Windows.Forms.DragDropEffects.All); }
/// <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--; } } }
private XmlElement createNoteNode(VsqEvent vsq_event, int pre_measure_clock) { var node = doc_.CreateElement("note"); node.AppendChild(createNode("posTick", vsq_event.Clock - pre_measure_clock)); node.AppendChild(createNode("durTick", vsq_event.ID.getLength())); node.AppendChild(createNode("noteNum", vsq_event.ID.Note)); node.AppendChild(createNode("velocity", vsq_event.ID.Dynamics)); node.AppendChild(createNode("lyric", vsq_event.ID.LyricHandle.getLyricAt(0).Phrase)); node.AppendChild(createNode("phnms", vsq_event.ID.LyricHandle.getLyricAt(0).getPhoneticSymbol())); { var style = doc_.CreateElement("noteStyle"); style.AppendChild(createNode("attr", vsq_event.ID.DEMaccent).Attribute("id", "accent")); style.AppendChild(createNode("attr", vsq_event.ID.PMBendDepth).Attribute("id", "bendDep")); style.AppendChild(createNode("attr", vsq_event.ID.PMBendLength).Attribute("id", "bendLen")); style.AppendChild(createNode("attr", vsq_event.ID.DEMdecGainRate).Attribute("id", "decay")); style.AppendChild(createNode("attr", vsq_event.ID.isFallPortamento() ? 1 : 0).Attribute("id", "fallPort")); style.AppendChild(createNode("attr", 127).Attribute("id", "opening")); style.AppendChild(createNode("attr", vsq_event.ID.isRisePortamento() ? 1 : 0).Attribute("id", "risePort")); if (vsq_event.ID.VibratoHandle != null && vsq_event.ID.VibratoDelay < vsq_event.ID.getLength()) { int vibrato_length = vsq_event.ID.getLength() - vsq_event.ID.VibratoDelay; int percent = (int)(vibrato_length * 100.0 / vsq_event.ID.getLength()); style.AppendChild(createNode("attr", percent).Attribute("id", "vibLen")); style.AppendChild(createNode("attr", vsq_event.ID.VibratoHandle.Index).Attribute("id", "vibType")); style.AppendChild(createVibratoCurveNode(vsq_event.ID.VibratoHandle.getStartDepth(), vsq_event.ID.VibratoHandle.getDepthBP()).Attribute("id", "vibDep")); style.AppendChild(createVibratoCurveNode(vsq_event.ID.VibratoHandle.getStartRate(), vsq_event.ID.VibratoHandle.getRateBP()).Attribute("id", "vibRate")); } node.AppendChild(style); } return(node); }
public void propertyGrid_PropertyValueChanged(Object s, PropertyValueChangedEventArgs e) { AppManager.mMainWindow.setPrograssBarVisible(true); AppManager.mMainWindow.setPrograssBarName("应用属性"); Object[] selobj = propertyGrid.SelectedObjects; int len = selobj.Length; AppManager.mMainWindow.setPrograssBarMaxium(len); AppManager.mMainWindow.setPrograssBarValue(0); VsqEvent[] items = new VsqEvent[len]; for (int i = 0; i < len; i++) { SelectedEventEntry proxy = (SelectedEventEntry)selobj[i]; items[i] = proxy.editing; Application.DoEvents(); } CadenciiCommand run = new CadenciiCommand(VsqCommand.generateCommandEventReplaceRange(m_track, items)); if (CommandExecuteRequired != null) { CommandExecuteRequired(this, run); } for (int i = 0; i < len; i++) { AppManager.itemSelection.addEvent(items[i].InternalID); AppManager.mMainWindow.setPrograssBarValue(i); Application.DoEvents(); } propertyGrid.Refresh(); setEditing(false); AppManager.mMainWindow.setPrograssBarVisible(false); }
public void testReflectVibratoPitch() { var tempoTable = new TempoVector(); var pitchBend = new VsqBPList( CurveType.PIT.getName(), CurveType.PIT.getDefault(), CurveType.PIT.getMinimum(), CurveType.PIT.getMaximum() ); var pitchBendSensitivity = new VsqBPList( CurveType.PIT.getName(), CurveType.PIT.getDefault(), CurveType.PIT.getMinimum(), CurveType.PIT.getMaximum() ); pitchBend.add( 0, 8191 ); pitchBendSensitivity.add( 0, 2 ); var generator = new AquesTone2WaveGeneratorStub(); var item = new VsqEvent( 0, new VsqID() ); item.ID.type = VsqIDType.Anote; item.ID.VibratoHandle = new VibratoHandle(); item.ID.VibratoHandle.StartRate = 0x40; item.ID.VibratoHandle.RateBP.clear(); item.ID.VibratoHandle.StartDepth = 0x40; item.ID.VibratoHandle.DepthBP.clear(); item.ID.setLength( 480 ); item.ID.VibratoDelay = 430; item.ID.VibratoHandle.setLength( 50 ); generator.reflectVibratoPitch( item, pitchBend, pitchBendSensitivity, tempoTable ); { var expectedPit = new Dictionary<int, int> { { 0, 8191 }, { 430, 5461 }, { 431, 5467 }, { 432, 5484 }, { 433, 5514 }, { 434, 5555 }, { 435, 5608 }, { 436, 5672 }, { 437, 5748 }, { 438, 5835 }, { 439, 5932 }, { 440, 6041 }, { 441, 6096 }, { 442, 6151 }, { 443, 6205 }, { 444, 6257 }, { 445, 6309 }, { 446, 6360 }, { 447, 6410 }, { 448, 6459 }, { 449, 6507 }, { 450, 6553 }, { 451, 6598 }, { 452, 6642 }, { 453, 6684 }, { 454, 6725 }, { 455, 6764 }, { 456, 6802 }, { 457, 6838 }, { 458, 6873 }, { 459, 6906 }, { 460, 6937 }, { 461, 6967 }, { 462, 6994 }, { 463, 7020 }, { 464, 7044 }, { 465, 7066 }, { 466, 7087 }, { 467, 7105 }, { 468, 7121 }, { 469, 7136 }, { 470, 7148 }, { 471, 6989 }, { 472, 6826 }, { 473, 6660 }, { 474, 6491 }, { 475, 6320 }, { 476, 6149 }, { 477, 5976 }, { 478, 5804 }, { 479, 5632 }, { 480, 8191 } }; Assert.AreEqual( expectedPit.Count, pitchBend.size() ); int i = 0; foreach ( var pitInfo in expectedPit ) { Assert.AreEqual( pitInfo.Key, pitchBend.getKeyClock( i ) ); Assert.AreEqual( pitInfo.Value, pitchBend.getElementA( i ) ); ++i; } } { var expectedPbs = new Dictionary<int, int> { { 0, 2 }, { 430, 3 }, { 480, 2 } }; Assert.AreEqual( expectedPbs.Count, pitchBendSensitivity.size() ); int i = 0; foreach ( var pbsInfo in expectedPbs ) { Assert.AreEqual( pbsInfo.Key, pitchBendSensitivity.getKeyClock( i ) ); Assert.AreEqual( pbsInfo.Value, pitchBendSensitivity.getElementA( i ) ); ++i; } } }
private XmlElement createMusicalPartSingerNode(VsqEvent @event, int pre_measure_clock) { var node = doc_.CreateElement("singer"); node.AppendChild(createNode("posTick", @event.Clock - pre_measure_clock)); node.AppendChild(createNode("vBS", @event.ID.IconHandle.Language)); node.AppendChild(createNode("vPC", @event.ID.IconHandle.Program)); return(node); }
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; } } }
public UtauSymbolSplitor(VsqFileEx mVsq, VsqEvent curEvent, Dictionary <int, double> PitchBrust, List <VsqEvent> VibstrBrustEvents, cadencii.utau.UtauVoiceDB db) { oriPitchBrust = PitchBrust; oriVibstrBrustEvents = VibstrBrustEvents; oriEvent = curEvent; dstVibstrBrustEvents.Add(oriEvent, oriVibstrBrustEvents); dstPitchBrust.Add(oriEvent, oriPitchBrust); dstParentTable.Add(oriEvent, oriEvent); vdb = db; this.mVsq = mVsq; }
public static void Main( string[] args ){ if( args.Length < 3 ){ Console.WriteLine( "makeMids [words-list] [singer(ex. Miku)] [DSB(ex. DSB303)] [extension(ex. .vsq)] [start-index]" ); return; } string list = args[0]; string singer = args[1]; string dsb = args[2]; string ext = args[3]; int start_index = 0; if( args.Length >= 5 ){ start_index = int.Parse( args[4] ); } if( !Directory.Exists( singer ) ){ Directory.CreateDirectory( singer ); } using( StreamReader sr = new StreamReader( list ) ){ string line = ""; VsqFile src = new VsqFile( singer, 2, 4, 4, 500000 ); VsqFile vsq = (VsqFile)src.clone(); int clock = 480 * 4 * 2; int count = 0; int numVsqs = start_index; while( (line = sr.ReadLine()) != null ){ VsqEvent item = new VsqEvent(); item.Clock = clock; item.ID = new VsqID(); item.ID.type = VsqIDType.Anote; item.ID.setLength( 240 ); item.ID.Note = 64; item.ID.LyricHandle = new LyricHandle(); item.ID.LyricHandle.L0 = new Lyric( line, "u:" ); vsq.Track.get( 1 ).addEvent( item, count + 1 ); clock += 240; count++; if( count > 5000 ){ vsq.Track.get( 1 ).getCommon().Version = dsb; vsq.Track.get( 1 ).sortEvent(); vsq.write( singer + "\\" + numVsqs + ext ); numVsqs++; vsq = null; vsq = (VsqFile)src.clone(); clock = 480 * 4 * 2; count = 0; } } if( count > 0 ){ vsq.Track.get( 1 ).getCommon().Version = dsb; vsq.Track.get( 1 ).sortEvent(); vsq.write( singer + "\\" + numVsqs + ext ); } } }
/// <summary> /// Initialize by VsqEvent object. /// </summary> /// <param name="item"></param> /// <param name="timesig_table"></param> public TiedEvent(VsqEvent item, TimesigVector timesig_table, TempoVector tempo_table) { Init(timesig_table, tempo_table, item.Clock, item.ID.getLength(), item.ID.Note, false); if (notes_.Count > 0 && item.ID.LyricHandle != null && item.ID.LyricHandle.getCount() > 0) { var lyric = new lyric(); lyric.text.Add(new textelementdata()); lyric.text.First.Value = item.ID.LyricHandle.getLyricAt(0).Phrase; notes_[0].lyric = new lyric[] { lyric }; } }
public string __DEBUG__toString() { string phase = ""; for (int i = 0; i < track.getEventCount(); i++) { VsqEvent itemi = track.getEvent(i); if (itemi.ID.type == VsqIDType.Anote) { phase += itemi.ID.LyricHandle.L0.Phrase; } } return(phase); }
public bool equals(Object obj1, Object obj2) { if (obj1 == null || obj2 == null) { return(false); } if (!(obj1 is VsqEvent) || !(obj2 is VsqEvent)) { return(false); } VsqEvent item1 = (VsqEvent)obj1; VsqEvent item2 = (VsqEvent)obj2; return(item1.ID.IconDynamicsHandle.IconID.Equals(item2.ID.IconDynamicsHandle.IconID)); }
public static bool Edit(VsqFile Vsq) { for (int i = 1; i < Vsq.Track.size(); i++) { for (int j = 0; j < Vsq.Track.get(i).getEventCount(); j++) { VsqEvent item = Vsq.Track.get(i).getEvent(j); if (item.ID.type == VsqIDType.Anote) { item.ID.LyricHandle.L0.Phrase = KanaDeRomanization.Attach(item.ID.LyricHandle.L0.Phrase); } } } return(true); }
public bool equals(Object obj1, Object obj2) { if (obj1 == null || obj2 == null) { return(false); } if (!(obj1 is VsqEvent) || !(obj2 is VsqEvent)) { return(false); } VsqEvent item1 = (VsqEvent)obj1; VsqEvent item2 = (VsqEvent)obj2; return(item1.ID.IconHandle.Program == item2.ID.IconHandle.Program); }
public void addEventAll(List <int> list) { clearTempo(); clearTimesig(); VsqEvent[] index = new VsqEvent[list.Count]; int count = 0; int c = list.Count; int selected = AppManager.getSelected(); for (Iterator <VsqEvent> itr = AppManager.getVsqFile().Track[selected].getEventIterator(); itr.hasNext();) { VsqEvent ev = itr.next(); int find = -1; for (int i = 0; i < c; i++) { if (list[i] == ev.InternalID) { find = i; break; } } if (0 <= find) { index[find] = ev; count++; } if (count == list.Count) { break; } } for (int i = 0; i < index.Length; i++) { try { if (!isEventContains(selected, index[i].InternalID)) { mEvents.Add(new SelectedEventEntry(selected, index[i], (VsqEvent)index[i].clone())); } } catch {; } } #if ENABLE_PROPERTY AppManager.propertyPanel.updateValue(selected); #endif checkSelectedItemExistence(); }
public static bool Edit(VsqFile vsq) { int track = 1; InputBox ib = new InputBox("Input target track index"); ib.setResult(track.ToString()); if (ib.ShowDialog() != DialogResult.OK) { return(false); } if (!int.TryParse(ib.getResult(), out track)) { MessageBox.Show("integer parse error"); return(false); } if (track <= 0 || vsq.Track.Count <= track) { MessageBox.Show("invalid target track"); return(false); } using (SaveFileDialog sfd = new SaveFileDialog()) { if (sfd.ShowDialog() != DialogResult.OK) { return(false); } using (StreamWriter sw = new StreamWriter(sfd.FileName, false, Encoding.GetEncoding(932))) { sw.WriteLine("vlf\t2.0"); sw.WriteLine("vlfpart\tPhrase1\t0\t0"); for (int i = 0; i < vsq.Track[track].getEventCount(); i++) { VsqEvent ve = vsq.Track[track].getEvent(i); if (ve.ID.type == VsqIDType.Anote) { string symbol = ""; for (int j = 0; j < ve.ID.LyricHandle.L0.getPhoneticSymbolList().Count; j++) { symbol += (" " + ve.ID.LyricHandle.L0.getPhoneticSymbolList()[j]); } symbol = symbol.Trim(); sw.WriteLine(ve.ID.LyricHandle.L0.Phrase + "\t" + symbol + "\t0"); } } } } return(true); }
/// <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); }
private void addEventCor(int id, bool silent) { clearTempo(); clearTimesig(); int selected = AppManager.getSelected(); for (Iterator <VsqEvent> itr = AppManager.getVsqFile().Track[selected].getEventIterator(); itr.hasNext();) { VsqEvent ev = itr.next(); if (ev.InternalID == id) { if (isEventContains(selected, id)) { // すでに選択されていた場合 int count = mEvents.Count; for (int i = 0; i < count; i++) { SelectedEventEntry item = mEvents[i]; if (item.original.InternalID == id) { mEvents.RemoveAt(i); break; } } } mEvents.Add(new SelectedEventEntry(selected, ev, (VsqEvent)ev.clone())); if (!silent) { invokeSelectedEventChangedEvent(false); } break; } } if (!silent) { #if ENABLE_PROPERTY AppManager.propertyPanel.updateValue(selected); #endif } }
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; } } }
public void setUp() { fixture = new VsqEventList(); { var item = new VsqEvent( 0, new VsqID() ); item.ID.type = VsqIDType.Singer; fixture.add( item, 0 ); } { var item = new VsqEvent( 480, new VsqID() ); item.ID.type = VsqIDType.Anote; fixture.add( item, 1 ); } { var item = new VsqEvent( 480, new VsqID() ); item.ID.type = VsqIDType.Singer; fixture.add( item, 2 ); } { var item = new VsqEvent( 1920, new VsqID() ); item.ID.type = VsqIDType.Singer; fixture.add( item, 3 ); } }
public void setUp() { fixture = new VsqEventList(); { var item = new VsqEvent(0, new VsqID()); item.ID.type = VsqIDType.Singer; fixture.add(item, 0); } { var item = new VsqEvent(480, new VsqID()); item.ID.type = VsqIDType.Anote; fixture.add(item, 1); } { var item = new VsqEvent(480, new VsqID()); item.ID.type = VsqIDType.Singer; fixture.add(item, 2); } { var item = new VsqEvent(1920, new VsqID()); item.ID.type = VsqIDType.Singer; fixture.add(item, 3); } }
/// <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); } } }
public void begin(long total_samples, WorkerState state) { var mDriver = getDriver(); #if DEBUG sout.println("AquesToneRenderingRunner#begin; (mDriver==null)=" + (mDriver == null)); String file = System.IO.Path.Combine(System.Windows.Forms.Application.StartupPath, "AquesToneWaveGenerator.txt"); log = new System.IO.StreamWriter(file); log.AutoFlush = true; #endif if (mDriver == null) { #if DEBUG log.WriteLine("mDriver==null"); log.Close(); #endif exitBegin(); state.reportComplete(); return; } #if DEBUG sout.println("AquesToneRenderingRunner#begin; mDriver.loaded=" + mDriver.loaded); #endif if (!mDriver.loaded) { #if DEBUG log.WriteLine("mDriver.loaded=" + mDriver.loaded); log.Close(); #endif exitBegin(); state.reportComplete(); return; } mRunning = true; //mAbortRequired = false; mTotalSamples = total_samples; #if DEBUG sout.println("AquesToneWaveGenerator#begin; mTotalSamples=" + mTotalSamples); log.WriteLine("mTotalSamples=" + mTotalSamples); log.WriteLine("mTrimRemain=" + mTrimRemain); #endif VsqTrack track = mVsq.Track.get(mTrack); int BUFLEN = mSampleRate / 10; double[] left = new double[BUFLEN]; double[] right = new double[BUFLEN]; long saProcessed = 0; int saRemain = 0; int lastClock = 0; // 最後に処理されたゲートタイム // 最初にダミーの音を鳴らす // (最初に入るノイズを回避するためと、前回途中で再生停止した場合に無音から始まるようにするため) mDriver.resetAllParameters(); mDriver.process(left, right, BUFLEN); MidiEvent f_noteon = new MidiEvent(); f_noteon.firstByte = 0x90; f_noteon.data = new int[] { 0x40, 0x40 }; f_noteon.clock = 0; mDriver.send(new MidiEvent[] { f_noteon }); mDriver.process(left, right, BUFLEN); MidiEvent f_noteoff = new MidiEvent(); f_noteoff.firstByte = 0x80; f_noteoff.data = new int[] { 0x40, 0x7F }; mDriver.send(new MidiEvent[] { f_noteoff }); for (int i = 0; i < 3; i++) { mDriver.process(left, right, BUFLEN); } #if DEBUG log.WriteLine("pre-process done"); log.WriteLine("-----------------------------------------------------"); VsqTrack vsq_track = mVsq.Track.get(mTrack); for (Iterator <VsqEvent> itr = vsq_track.getNoteEventIterator(); itr.hasNext();) { VsqEvent item = itr.next(); log.WriteLine("c" + item.Clock + "; " + item.ID.LyricHandle.L0.Phrase); } #endif // レンダリング開始位置での、パラメータの値をセットしておく for (Iterator <VsqEvent> itr = track.getNoteEventIterator(); itr.hasNext();) { VsqEvent item = itr.next(); #if DEBUG sout.println("AquesToneWaveGenerator#begin; item.Clock=" + item.Clock); log.WriteLine("*********************************************************"); log.WriteLine("item.Clock=" + item.Clock); #endif long saNoteStart = (long)(mVsq.getSecFromClock(item.Clock) * mSampleRate); long saNoteEnd = (long)(mVsq.getSecFromClock(item.Clock + item.ID.getLength()) * mSampleRate); #if DEBUG log.WriteLine("saNoteStart=" + saNoteStart + "; saNoteEnd=" + saNoteEnd); #endif EventQueueSequence list = generateMidiEvent(mVsq, mTrack, lastClock, item.Clock + item.ID.getLength()); lastClock = item.Clock + item.ID.Length + 1; for (Iterator <Integer> itr2 = list.keyIterator(); itr2.hasNext();) { // まず直前までの分を合成 Integer clock = itr2.next(); #if DEBUG log.WriteLine("-------------------------------------------------------"); sout.println("AquesToneWaveGenerator#begin; clock=" + clock); #endif long saStart = (long)(mVsq.getSecFromClock(clock) * mSampleRate); saRemain = (int)(saStart - saProcessed); #if DEBUG log.WriteLine("saStart=" + saStart); log.WriteLine("saRemain=" + saRemain); #endif while (saRemain > 0) { if (state.isCancelRequested()) { goto heaven; } int len = saRemain > BUFLEN ? BUFLEN : saRemain; mDriver.process(left, right, len); waveIncoming(left, right, len); saRemain -= len; saProcessed += len; state.reportProgress(saProcessed); //mTotalAppend += len; <- waveIncomingで計算されるので } // MIDiイベントを送信 MidiEventQueue queue = list.get(clock); // まずnoteoff boolean noteoff_send = false; if (queue.noteoff.size() > 0) { #if DEBUG for (int i = 0; i < queue.noteoff.size(); i++) { String str = ""; MidiEvent itemi = queue.noteoff.get(i); str += "0x" + PortUtil.toHexString(itemi.firstByte, 2) + " "; for (int j = 0; j < itemi.data.Length; j++) { str += "0x" + PortUtil.toHexString(itemi.data[j], 2) + " "; } sout.println(typeof(AquesToneWaveGenerator) + "#begin; noteoff; " + str); } #endif mDriver.send(queue.noteoff.toArray(new MidiEvent[] { })); noteoff_send = true; } // parameterの変更 if (queue.param.size() > 0) { for (Iterator <ParameterEvent> itr3 = queue.param.iterator(); itr3.hasNext();) { ParameterEvent pe = itr3.next(); #if DEBUG sout.println(typeof(AquesToneWaveGenerator) + "#begin; param; index=" + pe.index + "; value=" + pe.value); #endif mDriver.setParameter(pe.index, pe.value); } } // ついでnoteon if (queue.noteon.size() > 0) { // 同ゲートタイムにピッチベンドも指定されている場合、同時に送信しないと反映されないようだ! if (queue.pit.size() > 0) { queue.noteon.addAll(queue.pit); queue.pit.clear(); } #if DEBUG for (int i = 0; i < queue.noteon.size(); i++) { String str = ""; MidiEvent itemi = queue.noteon.get(i); str += "0x" + PortUtil.toHexString(itemi.firstByte, 2) + " "; for (int j = 0; j < itemi.data.Length; j++) { str += "0x" + PortUtil.toHexString(itemi.data[j], 2) + " "; } sout.println(typeof(AquesToneWaveGenerator) + "#begin; noteon; " + str); } #endif mDriver.send(queue.noteon.toArray(new MidiEvent[] { })); } // PIT if (queue.pit.size() > 0 && !noteoff_send) { #if DEBUG for (int i = 0; i < queue.pit.size(); i++) { String str = ""; MidiEvent itemi = queue.pit.get(i); str += "0x" + PortUtil.toHexString(itemi.firstByte, 2) + " "; for (int j = 0; j < itemi.data.Length; j++) { str += "0x" + PortUtil.toHexString(itemi.data[j], 2) + " "; } sout.println(typeof(AquesToneWaveGenerator) + "#begin; pit; " + str); } #endif mDriver.send(queue.pit.toArray(new MidiEvent[] { })); } if (mDriver.getUi(mMainWindow) != null) { mDriver.getUi(mMainWindow).invalidateUi(); } } } // totalSamplesに足りなかったら、追加してレンダリング saRemain = (int)(mTotalSamples - mTotalAppend); #if DEBUG sout.println("AquesToneRenderingRunner#run; totalSamples=" + mTotalSamples + "; mTotalAppend=" + mTotalAppend + "; saRemain=" + saRemain); #endif while (saRemain > 0) { if (state.isCancelRequested()) { goto heaven; } int len = saRemain > BUFLEN ? BUFLEN : saRemain; mDriver.process(left, right, len); waveIncoming(left, right, len); saRemain -= len; saProcessed += len; state.reportProgress(saProcessed); //mTotalAppend += len; } heaven: #if DEBUG log.Close(); #endif exitBegin(); state.reportComplete(); }
public static void GenerateSinglePhone(int note, string singer, string file, double amp) { string renderer = ""; SingerConfig[] singers1 = VocaloSysUtil.getSingerConfigs(SynthesizerType.VOCALOID1); int c = singers1.Length; string first_found_singer = ""; string first_found_renderer = ""; for (int i = 0; i < c; i++) { if (first_found_singer.Equals("")) { first_found_singer = singers1[i].VOICENAME; first_found_renderer = VsqFileEx.RENDERER_DSB2; } if (singers1[i].VOICENAME.Equals(singer)) { renderer = VsqFileEx.RENDERER_DSB2; break; } } SingerConfig[] singers2 = VocaloSysUtil.getSingerConfigs(SynthesizerType.VOCALOID2); c = singers2.Length; for (int i = 0; i < c; i++) { if (first_found_singer.Equals("")) { first_found_singer = singers2[i].VOICENAME; first_found_renderer = VsqFileEx.RENDERER_DSB3; } if (singers2[i].VOICENAME.Equals(singer)) { renderer = VsqFileEx.RENDERER_DSB3; break; } } foreach (var sc in AppManager.editorConfig.UtauSingers) { if (first_found_singer.Equals("")) { first_found_singer = sc.VOICENAME; first_found_renderer = VsqFileEx.RENDERER_UTU0; } if (sc.VOICENAME.Equals(singer)) { renderer = VsqFileEx.RENDERER_UTU0; break; } } VsqFileEx vsq = new VsqFileEx(singer, 1, 4, 4, 500000); if (renderer.Equals("")) { singer = first_found_singer; renderer = first_found_renderer; } vsq.Track[1].getCommon().Version = renderer; VsqEvent item = new VsqEvent(1920, new VsqID(0)); item.ID.LyricHandle = new LyricHandle("あ", "a"); item.ID.setLength(480); item.ID.Note = note; item.ID.VibratoHandle = null; item.ID.type = VsqIDType.Anote; vsq.Track[1].addEvent(item); vsq.updateTotalClocks(); int ms_presend = 500; string tempdir = Path.Combine(AppManager.getCadenciiTempDir(), AppManager.getID()); if (!Directory.Exists(tempdir)) { try { PortUtil.createDirectory(tempdir); } catch (Exception ex) { Logger.write(typeof(FormGenerateKeySound) + ".GenerateSinglePhone; ex=" + ex + "\n"); serr.println("Program#GenerateSinglePhone; ex=" + ex); return; } } WaveWriter ww = null; try { ww = new WaveWriter(file); RendererKind kind = VsqFileEx.getTrackRendererKind(vsq.Track[1]); WaveGenerator generator = VSTiDllManager.getWaveGenerator(kind); int sample_rate = vsq.config.SamplingRate; FileWaveReceiver receiver = new FileWaveReceiver(file, 1, 16, sample_rate); generator.setReceiver(receiver); generator.setGlobalConfig(AppManager.editorConfig); #if DEBUG sout.println("FormGenerateKeySound#GenerateSinglePhone; sample_rate=" + sample_rate); #endif generator.init(vsq, 1, 0, vsq.TotalClocks, sample_rate); double total_sec = vsq.getSecFromClock(vsq.TotalClocks) + 1.0; WorkerStateImp state = new WorkerStateImp(); generator.begin((long)(total_sec * sample_rate), state); } catch (Exception ex) { serr.println("FormGenerateKeySound#GenerateSinglePhone; ex=" + ex); Logger.write(typeof(FormGenerateKeySound) + ".GenerateSinglePhone; ex=" + ex + "\n"); } finally { if (ww != null) { try { ww.close(); } catch (Exception ex2) { Logger.write(typeof(FormGenerateKeySound) + ".GenerateSinglePhone; ex=" + ex2 + "\n"); serr.println("FormGenerateKeySound#GenerateSinglePhone; ex2=" + ex2); } } } }
public static bool Edit(VsqFile vsq) { using (RenderAsUtau dlg = new RenderAsUtau()) { if (dlg.ShowDialog() == DialogResult.OK) { Singer = dlg.txtSinger.Text; Resampler = dlg.txtResampler.Text; WavTool = dlg.txtWavtool.Text; string script = Path.Combine(Application.StartupPath, Path.Combine("script", "Render As UTAU.cs")); //Script.ScriptPath; string temp_dir = Path.Combine(Path.GetDirectoryName(script), Path.GetFileNameWithoutExtension(script)); #if DEBUG if (!Directory.Exists(temp_dir)) { Directory.CreateDirectory(temp_dir); } StreamWriter sw = new StreamWriter(Path.Combine(temp_dir, "log.txt")); #endif // 原音設定を読み込み Dictionary <string, OtoArgs> config = new Dictionary <string, OtoArgs>(); string singer_name = Path.GetFileName(Singer); string config_file = Path.Combine(Singer, "oto.ini"); #if DEBUG sw.WriteLine("Singer=" + Singer); sw.WriteLine("singer_name=" + singer_name); sw.WriteLine("config_file=" + config_file); #endif if (File.Exists(config_file)) { using (cp932reader sr = new cp932reader(config_file)) { string line; while (sr.Peek() >= 0) { try { line = sr.ReadLine(); String[] spl = line.Split('='); String file_name = spl[0]; // あ.wav String a2 = spl[1]; // ,0,36,64,0,0 String a1 = Path.GetFileNameWithoutExtension(file_name); spl = a2.Split(','); OtoArgs oa = new OtoArgs(); oa.Alias = spl[0]; oa.msOffset = int.Parse(spl[1]); oa.msConsonant = int.Parse(spl[2]); oa.msBlank = int.Parse(spl[3]); oa.msPreUtterance = int.Parse(spl[4]); oa.msOverwrap = int.Parse(spl[5]); config.Add(a1, oa); } catch { } } } } int track = AppManager.getSelected(); List <Phon> phons = new List <Phon>(); if (!Directory.Exists(temp_dir)) { Directory.CreateDirectory(temp_dir); } int count = -1; double sec_end = 0; double sec_end_old = 0; for (Iterator <VsqEvent> itr = vsq.Track.get(track).getNoteEventIterator(); itr.hasNext();) { VsqEvent item = itr.next(); count++; double sec_start = vsq.getSecFromClock(item.Clock); sec_end_old = sec_end; sec_end = vsq.getSecFromClock(item.Clock + item.ID.Length); float t_temp = (float)(item.ID.Length / (sec_end - sec_start) / 8.0); if ((count == 0 && sec_start > 0.0) || (sec_start > sec_end_old)) { double sec_start2 = sec_end_old; double sec_end2 = sec_start; float t_temp2 = (float)(item.Clock / (sec_end2 - sec_start2) / 8.0); phons.Add(new Phon("R", Path.Combine(Singer, "R.wav"), item.Clock, t_temp2, true)); count++; } string lyric = item.ID.LyricHandle.L0.Phrase; string note = NoteStringFromNoteNumber(item.ID.Note); #if DEBUG sw.WriteLine("note=" + note); #endif string millisec = ((int)((sec_end - sec_start) * 1000) + 50).ToString(); //4_あ_C#4_550.wav string filename = Path.Combine(temp_dir, count + "_" + item.ID.Note + "_" + millisec + ".wav"); #if DEBUG sw.WriteLine("filename=" + filename); sw.WriteLine(); #endif if (File.Exists(filename)) { PortUtil.deleteFile(filename); } phons.Add(new Phon(lyric, filename, item.ID.Length, t_temp, false)); OtoArgs oa = new OtoArgs(); if (config.ContainsKey(lyric)) { oa = config[lyric]; } int velocity = 100; int moduration = 100; string flags = "L"; int time_percent = 100; // C4 100 L 0 550 0 0 100 100 string arg = "\"" + Path.Combine(Singer, lyric + ".wav") + "\" \"" + filename + "\" \"" + note + "\" " + time_percent + " " + flags + " " + oa.msOffset + " " + millisec + " " + oa.msConsonant + " " + oa.msBlank + " " + velocity + " " + moduration; using (System.Diagnostics.Process p = new System.Diagnostics.Process()) { p.StartInfo.FileName = (InvokeWithWine ? "wine \"" : "\"") + Resampler + "\""; p.StartInfo.Arguments = arg; p.StartInfo.WorkingDirectory = temp_dir; p.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden; p.Start(); p.WaitForExit(); } } #if DEBUG sw.Close(); #endif string filebase = "temp.wav"; string file = Path.Combine(temp_dir, filebase); if (File.Exists(file)) { PortUtil.deleteFile(file); } string file_whd = Path.Combine(temp_dir, filebase + ".whd"); if (File.Exists(file_whd)) { PortUtil.deleteFile(file_whd); } string file_dat = Path.Combine(temp_dir, filebase + ".dat"); if (File.Exists(file_dat)) { PortUtil.deleteFile(file_dat); } // wavtoolを呼び出す for (int i = 0; i < phons.Count; i++) { OtoArgs oa = new OtoArgs(); if (config.ContainsKey(phons[i].Lyric)) { oa = config[phons[i].Lyric]; } // 次の音符の先行発声とオーバーラップを取得 OtoArgs oa_next = new OtoArgs(); if (i + 1 < phons.Count) { if (config.ContainsKey(phons[i + 1].Lyric)) { oa_next = config[phons[i + 1].Lyric]; } } int mten = oa.msPreUtterance + oa_next.msOverwrap - oa_next.msPreUtterance; string arg = filebase + " \"" + phons[i].FileName + "\" 0 " + phons[i].ClockLength + "@" + string.Format("{0:f2}", phons[i].Tempo) + mten.ToString("+#;-#;0"); if (phons[i].ModeR) { arg += " 0 0"; } else { arg += " 0 5 35 0 100 100 100 " + oa.msOverwrap; // エンベロープ } using (System.Diagnostics.Process p = new System.Diagnostics.Process()) { p.StartInfo.FileName = (InvokeWithWine ? "wine \"" : "\"") + WavTool + "\""; p.StartInfo.Arguments = arg; p.StartInfo.WorkingDirectory = temp_dir; p.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden; p.Start(); p.WaitForExit(); } } // 波形とヘッダを結合 using (FileStream fs = new FileStream(file, FileMode.Create)) { string[] files = new string[] { file_whd, file_dat }; int buflen = 512; byte[] buff = new byte[buflen]; for (int i = 0; i < files.Length; i++) { using (FileStream fs2 = new FileStream(files[i], FileMode.Open)) { int len = fs2.Read(buff, 0, buflen); while (len > 0) { fs.Write(buff, 0, len); len = fs2.Read(buff, 0, buflen); } } } } // 後片付け foreach (Phon ph in phons) { if (!ph.ModeR) { if (File.Exists(ph.FileName)) { PortUtil.deleteFile(ph.FileName); } } } if (File.Exists(file_whd)) { PortUtil.deleteFile(file_whd); } if (File.Exists(file_dat)) { PortUtil.deleteFile(file_dat); } if (saveFileDialog.ShowDialog() == DialogResult.OK) { if (File.Exists(saveFileDialog.FileName)) { PortUtil.deleteFile(saveFileDialog.FileName); } LastWave = saveFileDialog.FileName; PortUtil.moveFile(file, saveFileDialog.FileName); } else { PortUtil.deleteFile(file); } return(true); } else { return(false); } } }
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 static ScriptReturnStatus Edit(VsqFileEx vsq) { // 選択状態のアイテムがなければ戻る if (AppManager.itemSelection.getEventCount() <= 0) { return(ScriptReturnStatus.NOT_EDITED); } // 現在のトラック int selected = AppManager.getSelected(); VsqTrack vsq_track = vsq.Track.get(selected); vsq_track.sortEvent(); // プラグイン情報の定義ファイル(plugin.txt)があるかどうかチェック string pluginTxtPath = s_plugin_txt_path; if (pluginTxtPath == "") { AppManager.showMessageBox("pluginTxtPath=" + pluginTxtPath); return(ScriptReturnStatus.ERROR); } if (!System.IO.File.Exists(pluginTxtPath)) { AppManager.showMessageBox("'" + pluginTxtPath + "' does not exists"); return(ScriptReturnStatus.ERROR); } // plugin.txtがあれば,プラグインの実行ファイルのパスを取得する System.Text.Encoding shift_jis = System.Text.Encoding.GetEncoding("Shift_JIS"); string name = ""; string exe_path = ""; using (StreamReader sr = new StreamReader(pluginTxtPath, shift_jis)) { string line = ""; while ((line = sr.ReadLine()) != null) { string[] spl = line.Split(new char[] { '=' }, StringSplitOptions.RemoveEmptyEntries); if (line.StartsWith("name=")) { name = spl[1]; } else if (line.StartsWith("execute=")) { exe_path = Path.Combine(Path.GetDirectoryName(pluginTxtPath), spl[1]); } } } if (exe_path == "") { return(ScriptReturnStatus.ERROR); } if (!System.IO.File.Exists(exe_path)) { AppManager.showMessageBox("'" + exe_path + "' does not exists"); return(ScriptReturnStatus.ERROR); } // 選択状態のアイテムの最初と最後がどこか調べる // clock_start, clock_endは,最終的にはPREV, NEXTを含んだ範囲を表すことになる // sel_start, sel_endはPREV, NEXTを含まない選択範囲を表す int id_start = -1; int clock_start = int.MaxValue; int id_end = -1; int clock_end = int.MinValue; int sel_start = 0; int sel_end = 0; for (Iterator <SelectedEventEntry> itr = AppManager.itemSelection.getEventIterator(); itr.hasNext();) { SelectedEventEntry item = itr.next(); if (item.original.ID.type != VsqIDType.Anote) { continue; } int clock = item.original.Clock; if (clock < clock_start) { id_start = item.original.InternalID; clock_start = clock; sel_start = clock; } clock += item.original.ID.getLength(); if (clock_end < clock) { id_end = item.original.InternalID; clock_end = clock; sel_end = clock; } } // 選択範囲の前後の音符を探す VsqEvent ve_prev = null; VsqEvent ve_next = null; VsqEvent l = null; for (Iterator <VsqEvent> itr = vsq_track.getNoteEventIterator(); itr.hasNext();) { VsqEvent item = itr.next(); if (item.InternalID == id_start) { if (l != null) { ve_prev = l; } } if (l != null) { if (l.InternalID == id_end) { ve_next = item; } } l = item; if (ve_prev != null && ve_next != null) { break; } } int next_rest_clock = -1; bool prev_is_rest = false; if (ve_prev != null) { // 直前の音符がある場合 if (ve_prev.Clock + ve_prev.ID.getLength() == clock_start) { // 接続している clock_start = ve_prev.Clock; } else { // 接続していない int new_clock_start = ve_prev.Clock + ve_prev.ID.getLength(); clock_start = new_clock_start; } } else { // 無い場合 if (vsq.getPreMeasureClocks() < clock_start) { prev_is_rest = true; } int new_clock_start = vsq.getPreMeasureClocks(); clock_start = new_clock_start; } if (ve_next != null) { // 直後の音符がある場合 if (ve_next.Clock == clock_end) { // 接続している clock_end = ve_next.Clock + ve_next.ID.getLength(); } else { // 接続していない next_rest_clock = clock_end; clock_end = ve_next.Clock; } } // 作業用のVSQに,選択範囲のアイテムを格納 VsqFileEx v = (VsqFileEx)vsq.clone();// new VsqFile( "Miku", 1, 4, 4, 500000 ); // 選択トラックだけ残して他を削る for (int i = 1; i < selected; i++) { v.Track.removeElementAt(1); } for (int i = selected + 1; i < v.Track.size(); i++) { v.Track.removeElementAt(selected + 1); } // 選択トラックの音符を全消去する VsqTrack v_track = v.Track.get(1); v_track.MetaText.getEventList().clear(); for (Iterator <VsqEvent> itr = vsq_track.getNoteEventIterator(); itr.hasNext();) { VsqEvent item = itr.next(); if (clock_start <= item.Clock && item.Clock + item.ID.getLength() <= clock_end) { v_track.addEvent((VsqEvent)item.clone(), item.InternalID); } } // 最後のRを手動で追加.これは自動化できない if (next_rest_clock != -1) { VsqEvent item = (VsqEvent)ve_next.clone(); item.ID.LyricHandle.L0.Phrase = "R"; item.Clock = next_rest_clock; item.ID.setLength(clock_end - next_rest_clock); v_track.addEvent(item); } // 0~選択範囲の開始位置までを削除する v.removePart(0, clock_start); // vsq -> ustに変換 // キーがustのIndex, 値がInternalID TreeMap <int, int> map = new TreeMap <int, int>(); UstFile u = new UstFile(v, 1, map); u.write(Path.Combine(PortUtil.getApplicationStartupPath(), "u.ust")); // PREV, NEXTのIndex値を設定する if (ve_prev != null || prev_is_rest) { u.getTrack(0).getEvent(0).Index = UstFile.PREV_INDEX; } if (ve_next != null) { u.getTrack(0).getEvent(u.getTrack(0).getEventCount() - 1).Index = UstFile.NEXT_INDEX; } // ustファイルに出力 UstFileWriteOptions option = new UstFileWriteOptions(); option.settingCacheDir = false; option.settingOutFile = false; option.settingProjectName = false; option.settingTempo = true; option.settingTool1 = true; option.settingTool2 = true; option.settingTracks = false; option.settingVoiceDir = true; option.trackEnd = false; string temp = Path.GetTempFileName(); u.write(temp, option); StringBuilder before = new StringBuilder(); using (StreamReader sr = new StreamReader(temp, System.Text.Encoding.GetEncoding("Shift_JIS"))) { string line = ""; while ((line = sr.ReadLine()) != null) { before.AppendLine(line); } } String md5_before = PortUtil.getMD5FromString(before.ToString()); // プラグインの実行ファイルを起動 Utau_Plugin_Invoker dialog = new Utau_Plugin_Invoker(exe_path, temp); dialog.ShowDialog(); StringBuilder after = new StringBuilder(); using (StreamReader sr = new StreamReader(temp, System.Text.Encoding.GetEncoding("Shift_JIS"))) { string line = ""; while ((line = sr.ReadLine()) != null) { after.AppendLine(line); } } String md5_after = PortUtil.getMD5FromString(after.ToString()); if (md5_before == md5_after) { // 編集されなかったようだ return(ScriptReturnStatus.NOT_EDITED); } // プラグインの実行結果をustオブジェクトにロード UstFile r = new UstFile(temp); if (r.getTrackCount() < 1) { return(ScriptReturnStatus.ERROR); } // 変更のなかったものについてはプラグインは記録してこないので, // 最初の値を代入するようにする UstTrack utrack_src = u.getTrack(0); UstTrack utrack_dst = r.getTrack(0); for (int i = 0; i < utrack_dst.getEventCount(); i++) { UstEvent ue_dst = utrack_dst.getEvent(i); int index = ue_dst.Index; UstEvent ue_src = utrack_src.findEventFromIndex(index); if (ue_src == null) { continue; } if (!ue_dst.isEnvelopeSpecified() && ue_src.isEnvelopeSpecified()) { ue_dst.setEnvelope(ue_src.getEnvelope()); } if (!ue_dst.isIntensitySpecified() && ue_src.isIntensitySpecified()) { ue_dst.setIntensity(ue_src.getIntensity()); } if (!ue_dst.isLengthSpecified() && ue_src.isLengthSpecified()) { ue_dst.setLength(ue_src.getLength()); } if (!ue_dst.isLyricSpecified() && ue_src.isLyricSpecified()) { ue_dst.setLyric(ue_src.getLyric()); } if (!ue_dst.isModurationSpecified() && ue_src.isModurationSpecified()) { ue_dst.setModuration(ue_src.getModuration()); } if (!ue_dst.isNoteSpecified() && ue_src.isNoteSpecified()) { ue_dst.setNote(ue_src.getNote()); } if (!ue_dst.isPBTypeSpecified() && ue_src.isPBTypeSpecified()) { ue_dst.setPBType(ue_src.getPBType()); } if (!ue_dst.isPitchesSpecified() && ue_src.isPitchesSpecified()) { ue_dst.setPitches(ue_src.getPitches()); } if (!ue_dst.isPortamentoSpecified() && ue_src.isPortamentoSpecified()) { ue_dst.setPortamento(ue_src.getPortamento()); } if (!ue_dst.isPreUtteranceSpecified() && ue_src.isPreUtteranceSpecified()) { ue_dst.setPreUtterance(ue_src.getPreUtterance()); } if (!ue_dst.isStartPointSpecified() && ue_src.isStartPointSpecified()) { ue_dst.setStartPoint(ue_src.getStartPoint()); } if (!ue_dst.isTempoSpecified() && ue_src.isTempoSpecified()) { ue_dst.setTempo(ue_src.getTempo()); } if (!ue_dst.isVibratoSpecified() && ue_src.isVibratoSpecified()) { ue_dst.setVibrato(ue_src.getVibrato()); } if (!ue_dst.isVoiceOverlapSpecified() && ue_src.isVoiceOverlapSpecified()) { ue_dst.setVoiceOverlap(ue_src.getVoiceOverlap()); } } // PREVとNEXT含めて,clock_startからclock_endまでプラグインに渡したけれど, // それが伸びて帰ってきたか縮んで帰ってきたか. int ret_length = 0; UstTrack r_track = r.getTrack(0); int size = r_track.getEventCount(); for (int i = 0; i < size; i++) { UstEvent ue = r_track.getEvent(i); // 戻りのustには,変更があったものしか記録されていない int ue_length = ue.getLength(); if (!ue.isLengthSpecified() && map.ContainsKey(ue.Index)) { int internal_id = map[ue.Index]; VsqEvent found_item = vsq_track.findEventFromID(internal_id); if (found_item != null) { ue_length = found_item.ID.getLength(); } } // PREV, ENDの場合は長さに加えない if (ue.Index != UstFile.NEXT_INDEX && ue.Index != UstFile.PREV_INDEX) { ret_length += ue_length; } } // 伸び縮みがあった場合 // 伸ばしたり縮めたりするよ int delta = ret_length - (sel_end - sel_start); if (delta > 0) { // のびた vsq.insertBlank(selected, sel_end, delta); } else if (delta < 0) { // 縮んだ vsq.removePart(selected, sel_end + delta, sel_end); } // r_trackの内容をvsq_trackに転写 size = r_track.getEventCount(); int c = clock_start; for (int i = 0; i < size; i++) { UstEvent ue = r_track.getEvent(i); if (ue.Index == UstFile.NEXT_INDEX || ue.Index == UstFile.PREV_INDEX) { // PREVとNEXTは単に無視する continue; } int ue_length = ue.getLength(); if (map.containsKey(ue.Index)) { // 既存の音符の編集 VsqEvent target = vsq_track.findEventFromID(map[ue.Index]); if (target == null) { // そんなばかな・・・ continue; } if (!ue.isLengthSpecified()) { ue_length = target.ID.getLength(); } if (target.UstEvent == null) { target.UstEvent = (UstEvent)ue.clone(); } // utau固有のパラメータを転写 // pitchは後でやるので無視していい // テンポもあとでやるので無視していい if (ue.isEnvelopeSpecified()) { target.UstEvent.setEnvelope(ue.getEnvelope()); } if (ue.isModurationSpecified()) { target.UstEvent.setModuration(ue.getModuration()); } if (ue.isPBTypeSpecified()) { target.UstEvent.setPBType(ue.getPBType()); } if (ue.isPortamentoSpecified()) { target.UstEvent.setPortamento(ue.getPortamento()); } if (ue.isPreUtteranceSpecified()) { target.UstEvent.setPreUtterance(ue.getPreUtterance()); } if (ue.isStartPointSpecified()) { target.UstEvent.setStartPoint(ue.getStartPoint()); } if (ue.isVibratoSpecified()) { target.UstEvent.setVibrato(ue.getVibrato()); } if (ue.isVoiceOverlapSpecified()) { target.UstEvent.setVoiceOverlap(ue.getVoiceOverlap()); } // vocaloid, utauで同じ意味のパラメータを転写 if (ue.isIntensitySpecified()) { target.UstEvent.setIntensity(ue.getIntensity()); target.ID.Dynamics = ue.getIntensity(); } if (ue.isLengthSpecified()) { target.UstEvent.setLength(ue.getLength()); target.ID.setLength(ue.getLength()); } if (ue.isLyricSpecified()) { target.UstEvent.setLyric(ue.getLyric()); target.ID.LyricHandle.L0.Phrase = ue.getLyric(); } if (ue.isNoteSpecified()) { target.UstEvent.setNote(ue.getNote()); target.ID.Note = ue.getNote(); } } else { // マップに入っていないので,新しい音符の追加だと思う if (ue.getLyric() == "R") { // 休符.なにもしない } else { VsqEvent newe = new VsqEvent(); newe.Clock = c; newe.UstEvent = (UstEvent)ue.clone(); newe.ID = new VsqID(); AppManager.editorConfig.applyDefaultSingerStyle(newe.ID); if (ue.isIntensitySpecified()) { newe.ID.Dynamics = ue.getIntensity(); } newe.ID.LyricHandle = new LyricHandle("あ", "a"); if (ue.isLyricSpecified()) { newe.ID.LyricHandle.L0.Phrase = ue.getLyric(); } newe.ID.Note = ue.getNote(); newe.ID.setLength(ue.getLength()); newe.ID.type = VsqIDType.Anote; // internal id はaddEventメソッドで自動で割り振られる vsq_track.addEvent(newe); } } // テンポの追加がないかチェック if (ue.isTempoSpecified()) { insertTempoInto(vsq, c, ue.getTempo()); } c += ue_length; } // ピッチを転写 // pitのデータがほしいので,PREV, NEXTを削除して,VsqFileにコンバートする UstFile uf = (UstFile)r.clone(); // prev, nextを削除 UstTrack uf_track = uf.getTrack(0); for (int i = 0; i < uf_track.getEventCount();) { UstEvent ue = uf_track.getEvent(i); if (ue.Index == UstFile.NEXT_INDEX || ue.Index == UstFile.PREV_INDEX) { uf_track.removeEventAt(i); } else { i++; } } uf.updateTempoInfo(); // VsqFileにコンバート VsqFile uf_vsq = new VsqFile(uf); // uf_vsqの最初のトラックの0からret_lengthクロックまでが, // vsq_trackのsel_startからsel_start+ret_lengthクロックまでに対応する. // まずPBSをコピーする CurveType[] type = new CurveType[] { CurveType.PBS, CurveType.PIT }; foreach (CurveType ct in type) { // コピー元を取得 VsqBPList src = uf_vsq.Track[1].getCurve(ct.getName()); if (src != null) { // コピー先を取得 VsqBPList dst = vsq_track.getCurve(ct.getName()); if (dst == null) { // コピー先がnullだった場合は作成 dst = new VsqBPList(ct.getName(), ct.getDefault(), ct.getMinimum(), ct.getMaximum()); vsq_track.setCurve(ct.getName(), dst); } // あとで復元するので,最終位置での値を保存しておく int value_at_end = dst.getValue(sel_start + ret_length); // 復元するかどうか.最終位置にそもそもデータ点があれば復帰の必要がないので. bool do_revert = (dst.findIndexFromClock(sel_start + ret_length) < 0); // [sel_start, sel_start + ret_length)の範囲の値を削除しておく size = dst.size(); for (int i = size - 1; i >= 0; i--) { int cl = dst.getKeyClock(i); if (sel_start <= cl && cl < sel_start + ret_length) { dst.removeElementAt(i); } } // コピーを実行 size = src.size(); for (int i = 0; i < size; i++) { int cl = src.getKeyClock(i); if (ret_length <= cl) { break; } int value = src.getElementA(i); dst.add(cl + sel_start, value); } // コピー後,最終位置での値が元と異なる場合,元に戻すようにする if (do_revert && dst.getValue(sel_start + ret_length) != value_at_end) { dst.add(sel_start + ret_length, value_at_end); } } } return(ScriptReturnStatus.EDITED); }
public static ScriptReturnStatus Edit( VsqFileEx vsq ){ if( AppManager.getSelectedEventCount() <= 0 ){ return ScriptReturnStatus.NOT_EDITED; } 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; } 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; } // ustを用意 ------------------------------------------------------------------------ // 方針は,一度VsqFileに音符を格納->UstFile#.ctor( VsqFile )を使って一括変換 // メイン画面で選択されているアイテムを列挙 List<VsqEvent> items = new List<VsqEvent>(); for( Iterator itr = AppManager.getSelectedEventIterator(); itr.hasNext(); ){ SelectedEventEntry item_itr = (SelectedEventEntry)itr.next(); if( item_itr.original.ID.type == VsqIDType.Anote ){ items.Add( (VsqEvent)item_itr.original.clone() ); } } items.Sort(); // R用音符のテンプレート VsqEvent template = new VsqEvent(); template.ID.type = VsqIDType.Anote; template.ID.LyricHandle = new LyricHandle( "R", "" ); int count = items.Count; // アイテムが2個以上の場合は、間にRを挿入する必要があるかどうか判定 if( count > 1 ){ List<VsqEvent> add = new List<VsqEvent>(); // 追加するR VsqEvent last_event = items[0]; for( int i = 1; i < count; i++ ){ VsqEvent item = items[i]; if( last_event.Clock + last_event.ID.Length < item.Clock ){ VsqEvent add_temp = (VsqEvent)template.clone(); add_temp.Clock = last_event.Clock + last_event.ID.Length; add_temp.ID.Length = item.Clock - add_temp.Clock; add.Add( add_temp ); } last_event = item; } foreach( VsqEvent v in add ){ items.Add( v ); } items.Sort(); } // ヘッダ int TEMPO = 120; // 選択アイテムの直前直後に未選択アイテムがあるかどうかを判定 int clock_begin = items[0].Clock; int clock_end = items[items.Count - 1].Clock; VsqTrack vsq_track = vsq.Track.get( AppManager.getSelected() ); VsqEvent tlast_event = null; VsqEvent prev = null; VsqEvent next = null; // VsqFile -> UstFileのコンバート VsqFile conv = new VsqFile( "Miku", 2, 4, 4, (int)(6e7 / TEMPO) ); VsqTrack conv_track = conv.Track.get( 1 ); for( Iterator itr = vsq_track.getNoteEventIterator(); itr.hasNext(); ){ VsqEvent item_itr = (VsqEvent)itr.next(); if( item_itr.Clock == clock_begin ){ if( tlast_event != null ){ // アイテムあり if( tlast_event.Clock + tlast_event.ID.Length == clock_begin ){ // ゲートタイム差0で接続 prev = (VsqEvent)tlast_event.clone(); }else{ // 時間差アリで接続 prev = (VsqEvent)template.clone(); prev.Clock = tlast_event.Clock + tlast_event.ID.Length; prev.ID.Length = clock_begin - (tlast_event.Clock + tlast_event.ID.Length); } } } tlast_event = item_itr; if( item_itr.Clock == clock_end ){ if( itr.hasNext() ){ VsqEvent foo = (VsqEvent)itr.next(); int clock_end_end = clock_end + items[items.Count - 1].ID.Length; if( foo.Clock == clock_end_end ){ // ゲートタイム差0で接続 next = (VsqEvent)foo.clone(); }else{ // 時間差アリで接続 next = (VsqEvent)template.clone(); next.Clock = clock_end_end; next.ID.Length = foo.Clock - clock_end_end; } } break; } } // [#PREV]を追加 if( prev != null ){ prev.Clock -= clock_begin; conv_track.addEvent( prev ); } // ゲートタイムを計算しながら追加 count = items.Count; for( int i = 0; i < count; i++ ){ VsqEvent itemi = items[i]; itemi.Clock -= clock_begin; conv_track.addEvent( itemi ); } // [#NEXT]を追加 if( next != null ){ next.Clock -= clock_begin; conv_track.addEvent( next ); } // PIT, PBSを追加 copyCurve( vsq_track.getCurve( "pit" ), conv_track.getCurve( "pit" ), clock_begin ); copyCurve( vsq_track.getCurve( "pbs" ), conv_track.getCurve( "pbs" ), clock_begin ); string temp = Path.GetTempFileName(); UstFile tust = new UstFile( conv, 1 ); if( prev != null ){ tust.getTrack( 0 ).getEvent( 0 ).Index = int.MinValue; } if( next != null ){ tust.getTrack( 0 ).getEvent( tust.getTrack( 0 ).getEventCount() - 1 ).Index = int.MaxValue; } tust.write( temp ); // 起動 ----------------------------------------------------------------------------- StartPluginArgs arg = new StartPluginArgs(); arg.exePath = exe_path; arg.tmpFile = temp; System.Threading.Thread t = new System.Threading.Thread( new System.Threading.ParameterizedThreadStart( runPlugin ) ); s_finished = false; t.Start( arg ); while( !s_finished ){ Application.DoEvents(); } // 結果を反映 ----------------------------------------------------------------------- UstFile ust = null; try{ ust = new UstFile( temp ); }catch( Exception ex ){ AppManager.showMessageBox( "invalid ust file; ex=" + ex ); return ScriptReturnStatus.ERROR; } int track_count = ust.getTrackCount(); for( int i = 0; i < track_count; i++ ){ UstTrack track = ust.getTrack( i ); int event_count = track.getEventCount(); for( int j = 0; j < event_count; j++ ){ UstEvent itemj = track.getEvent( j ); if( itemj.Index == int.MinValue ){ AppManager.showMessageBox( "[#PREV]" ); }else if( itemj.Index == int.MaxValue ){ AppManager.showMessageBox( "[#NEXT]" ); }else{ AppManager.showMessageBox( itemj.Index + "" ); } } } try{ System.IO.File.Delete( temp ); }catch( Exception ex ){ } return ScriptReturnStatus.ERROR; }
/// <summary> /// 音符に付随するピッチベンドの情報を、PIT・PBS カーブに反映する /// </summary> /// <param name="item">音符</param> /// <param name="pitchBend">PIT カーブ</param> /// <param name="pitchBendSensitivity">PBS カーブ</param> /// <param name="tempoTable">テンポ情報</param> protected void reflectNoteEventPitch( VsqEvent item, VsqBPList pitchBend, VsqBPList pitchBendSensitivity, TempoVector tempoTable ) { if ( item.ID.type != VsqIDType.Anote ) return; // AquesTone2 では、note on と同 clock にピッチベンドイベントを送らないと音程が反映されないので、必ずピッチイベントが送られるようにする pitchBend.add( item.Clock, pitchBend.getValue( item.Clock ) ); if ( item.ID.VibratoHandle == null ) { return; } int startClock = item.Clock + item.ID.VibratoDelay; int vibratoLength = item.ID.Length - item.ID.VibratoDelay; var iterator = new VibratoPointIteratorByClock( tempoTable, item.ID.VibratoHandle.RateBP, item.ID.VibratoHandle.StartRate, item.ID.VibratoHandle.DepthBP, item.ID.VibratoHandle.StartDepth, startClock, vibratoLength ); var pitContext = new ByRef<int>( 0 ); var pbsContext = new ByRef<int>( 0 ); int pitAtEnd = pitchBend.getValue( startClock + vibratoLength ); int pbsAtEnd = pitchBendSensitivity.getValue( startClock + vibratoLength ); var pitBackup = (VsqBPList)pitchBend.Clone(); var pbsBackup = (VsqBPList)pitchBendSensitivity.Clone(); bool resetPBS = false; double maxNetPitchBendInCent = 0.0; for ( int clock = startClock; clock < startClock + vibratoLength && iterator.hasNext(); ++clock ) { double vibratoPitchBendInCent = iterator.next() * 100.0; int pit = pitchBend.getValue( clock, pitContext ); int pbs = pitchBendSensitivity.getValue( clock, pbsContext ); const double pow2_13 = 8192; double netPitchBendInCent = (pbs * pit / pow2_13) * 100.0 + vibratoPitchBendInCent; maxNetPitchBendInCent = Math.Max( maxNetPitchBendInCent, Math.Abs( netPitchBendInCent ) ); int draftPitchBend = (int)Math.Round( (netPitchBendInCent / 100.0) * pow2_13 / pbs ); if ( draftPitchBend < pitchBend.Minimum || pitchBend.Maximum < draftPitchBend ) { // pbs を変更せずにビブラートによるピッチベンドを反映しようとすると、 // pit が範囲を超えてしまう。 resetPBS = true; } else { if ( draftPitchBend != pit ) { pitchBend.add( clock, draftPitchBend ); } } } if ( !resetPBS ) { return; } pitchBend.Data = pitBackup.Data; // ピッチベンドの最大値を実現するのに必要なPBS int requiredPitchbendSensitivity = (int)Math.Ceiling( maxNetPitchBendInCent / 100.0 ); int pseudoMaxPitchbendSensitivity = 12; // AquesTone2 は最大 12 半音までベンドできる。 if ( requiredPitchbendSensitivity < pitchBendSensitivity.Minimum ) requiredPitchbendSensitivity = pitchBendSensitivity.Minimum; if ( pseudoMaxPitchbendSensitivity < requiredPitchbendSensitivity ) requiredPitchbendSensitivity = pseudoMaxPitchbendSensitivity; { int i = 0; while ( i < pitchBend.size() ) { var clock = pitchBend.getKeyClock( i ); if ( startClock <= clock && clock < startClock + vibratoLength ) { pitchBend.removeElementAt( i ); } else { ++i; } } } { int i = 0; while ( i < pitchBendSensitivity.size() ) { var clock = pitchBendSensitivity.getKeyClock( i ); if ( startClock <= clock && clock < startClock + vibratoLength ) { pitchBendSensitivity.removeElementAt( i ); } else { ++i; } } } if ( pitchBendSensitivity.getValue( startClock ) != requiredPitchbendSensitivity ) { pitchBendSensitivity.add( startClock, requiredPitchbendSensitivity ); } pitchBend.add( startClock + vibratoLength, pitAtEnd ); pitchBendSensitivity.add( startClock + vibratoLength, pbsAtEnd ); iterator.rewind(); pitContext.value = 0; pbsContext.value = 0; int lastPitchBend = pitchBend.getValue( startClock ); for ( int clock = startClock; clock < startClock + vibratoLength && iterator.hasNext(); ++clock ) { double vibratoPitchBendInCent = iterator.next() * 100.0; int pit = pitBackup.getValue( clock, pitContext ); int pbs = pbsBackup.getValue( clock, pbsContext ); const double pow2_13 = 8192; double netPitchBendInCent = (pbs * pit / pow2_13) * 100.0 + vibratoPitchBendInCent; maxNetPitchBendInCent = Math.Max( maxNetPitchBendInCent, Math.Abs( netPitchBendInCent ) ); int draftPitchBend = (int)Math.Round((netPitchBendInCent / 100.0) * pow2_13 / requiredPitchbendSensitivity); if ( draftPitchBend < pitchBend.Minimum ) draftPitchBend = pitchBend.Minimum; if ( pitchBend.Maximum < draftPitchBend ) draftPitchBend = pitchBend.Maximum; if ( draftPitchBend != lastPitchBend ) { pitchBend.add( clock, draftPitchBend ); lastPitchBend = draftPitchBend; } } }
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> /// xml要素から音符イベントを生成する /// </summary> /// <param name="note">xml要素</param> /// <param name="tickOffset">指定したxml要素が所属しているmusicalPartの、オフセットtick数</param> /// <returns>生成した音符イベント</returns> private static VsqEvent createNoteEvent(XmlNode note, int tickOffset) { int posTick = int.Parse(note["posTick"].InnerText); VsqEvent item = new VsqEvent(); item.Clock = posTick + tickOffset; item.ID = new VsqID(); item.ID.type = VsqIDType.Anote; item.ID.LyricHandle = new LyricHandle(); string lyric = note["lyric"].InnerText; XmlElement phnmsElement = note["phnms"]; string symbols = phnmsElement.InnerText; bool symbolsProtected = false; if (phnmsElement.HasAttribute("lock")) { int value = int.Parse(phnmsElement.Attributes["lock"].Value); symbolsProtected = value == 1; } item.ID.LyricHandle.L0.PhoneticSymbolProtected = symbolsProtected; item.ID.LyricHandle.L0.Phrase = lyric; item.ID.LyricHandle.L0.setPhoneticSymbol(symbols); item.ID.Note = int.Parse(note["noteNum"].InnerText); item.ID.setLength(int.Parse(note["durTick"].InnerText)); item.ID.Dynamics = int.Parse(note["velocity"].InnerText); var attributes = getNoteAttributes(note); if (attributes.ContainsKey("accent")) { item.ID.DEMaccent = attributes["accent"]; } if (attributes.ContainsKey("bendDep")) { item.ID.PMBendDepth = attributes["bendDep"]; } if (attributes.ContainsKey("bendLen")) { item.ID.PMBendLength = attributes["bendLen"]; } if (attributes.ContainsKey("decay")) { item.ID.DEMdecGainRate = attributes["decay"]; } if (attributes.ContainsKey("fallPort")) { item.ID.setFallPortamento(attributes["fallPort"] == 1); } if (attributes.ContainsKey("risePort")) { item.ID.setRisePortamento(attributes["risePort"] == 1); } // vibrato if (attributes.ContainsKey("vibLen") && attributes.ContainsKey("vibType")) { int lengthPercentage = attributes["vibLen"]; int vibratoType = attributes["vibType"] - 1; if (lengthPercentage > 0) { var vibratoHandle = new VibratoHandle(); int length = item.ID.getLength(); int duration = (int)(length * (lengthPercentage / 100.0)); vibratoHandle.setLength(duration); item.ID.VibratoDelay = length - duration; vibratoHandle.IconID = "$0404" + vibratoType.ToString("X4"); double delayRatio = (double)(length - duration) / (double)length; // VibDepth vibratoHandle.setDepthBP(getVibratoCurve(note, "vibDep", delayRatio)); // VibRate vibratoHandle.setRateBP(getVibratoCurve(note, "vibRate", delayRatio)); item.ID.VibratoHandle = vibratoHandle; } } return(item); }
public void testReflectVibratoPitch() { var tempoTable = new TempoVector(); var pitchBend = new VsqBPList(CurveType.PIT.getName(), CurveType.PIT.getDefault(), CurveType.PIT.getMinimum(), CurveType.PIT.getMaximum()); var pitchBendSensitivity = new VsqBPList(CurveType.PIT.getName(), CurveType.PIT.getDefault(), CurveType.PIT.getMinimum(), CurveType.PIT.getMaximum()); pitchBend.add(0, 8191); pitchBendSensitivity.add(0, 2); var generator = new AquesTone2WaveGeneratorStub(); var item = new VsqEvent(0, new VsqID()); item.ID.type = VsqIDType.Anote; item.ID.VibratoHandle = new VibratoHandle(); item.ID.VibratoHandle.StartRate = 0x40; item.ID.VibratoHandle.RateBP.clear(); item.ID.VibratoHandle.StartDepth = 0x40; item.ID.VibratoHandle.DepthBP.clear(); item.ID.setLength(480); item.ID.VibratoDelay = 430; item.ID.VibratoHandle.setLength(50); generator.reflectVibratoPitch(item, pitchBend, pitchBendSensitivity, tempoTable); { var expectedPit = new Dictionary <int, int> { { 0, 8191 }, { 430, 5461 }, { 431, 5467 }, { 432, 5484 }, { 433, 5514 }, { 434, 5555 }, { 435, 5608 }, { 436, 5672 }, { 437, 5748 }, { 438, 5835 }, { 439, 5932 }, { 440, 6041 }, { 441, 6096 }, { 442, 6151 }, { 443, 6205 }, { 444, 6257 }, { 445, 6309 }, { 446, 6360 }, { 447, 6410 }, { 448, 6459 }, { 449, 6507 }, { 450, 6553 }, { 451, 6598 }, { 452, 6642 }, { 453, 6684 }, { 454, 6725 }, { 455, 6764 }, { 456, 6802 }, { 457, 6838 }, { 458, 6873 }, { 459, 6906 }, { 460, 6937 }, { 461, 6967 }, { 462, 6994 }, { 463, 7020 }, { 464, 7044 }, { 465, 7066 }, { 466, 7087 }, { 467, 7105 }, { 468, 7121 }, { 469, 7136 }, { 470, 7148 }, { 471, 6989 }, { 472, 6826 }, { 473, 6660 }, { 474, 6491 }, { 475, 6320 }, { 476, 6149 }, { 477, 5976 }, { 478, 5804 }, { 479, 5632 }, { 480, 8191 } }; Assert.AreEqual(expectedPit.Count, pitchBend.size()); int i = 0; foreach (var pitInfo in expectedPit) { Assert.AreEqual(pitInfo.Key, pitchBend.getKeyClock(i)); Assert.AreEqual(pitInfo.Value, pitchBend.getElementA(i)); ++i; } } { var expectedPbs = new Dictionary <int, int> { { 0, 2 }, { 430, 3 }, { 480, 2 } }; Assert.AreEqual(expectedPbs.Count, pitchBendSensitivity.size()); int i = 0; foreach (var pbsInfo in expectedPbs) { Assert.AreEqual(pbsInfo.Key, pitchBendSensitivity.getKeyClock(i)); Assert.AreEqual(pbsInfo.Value, pitchBendSensitivity.getElementA(i)); ++i; } } }
public void reflectVibratoPitch( VsqEvent item, VsqBPList pitchBend, VsqBPList pitchBendSensitivity, TempoVector tempoTable ) { base.reflectNoteEventPitch( item, pitchBend, pitchBendSensitivity, tempoTable ); }
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); }
/*private int round5(float X) * { * return (int)(Math.Round(X / 5, 0) * 5); * }*/ public void SplitIt() { dstVibstrBrustEvents.Clear(); dstPitchBrust.Clear(); dstParentTable.Clear(); string PRO = oriEvent.ID.LyricHandle.L0.getPhoneticSymbol(); if (PRO.IndexOf(',') > 0) { if (oriEvent.UstEvent.SplitLength > 0) { int Len1 = 0; int Len2 = 0; int SplitTime = 0; Len2 = (int)oriEvent.UstEvent.SplitLength; Len1 = oriEvent.ID.getLength() - Len2; /*if (oriEvent.UstEvent.SplitisPercent) * { * Len2 = (int)(oriEvent.ID.getLength() * (oriEvent.UstEvent.SplitLength / 100.0)); * Len1 = oriEvent.ID.getLength() - Len2; * } * else * { * Len2 = (int)oriEvent.UstEvent.SplitLength; * Len1 = oriEvent.ID.getLength() - Len2; * } * if (Len1 <= 0) * { * Len1 = oriEvent.ID.getLength() / 2; * Len2 = oriEvent.ID.getLength() - Len1; * }*/ /*int PitchCountStartPoint=(int)Math.Round(oriEvent.Clock-oriEvent.UstEvent.getPreUtterance(),0); * Len1 = Cell5(PitchCountStartPoint + Len1) - PitchCountStartPoint; * Len2 = oriEvent.ID.getLength() - Len1; * SplitTime=(Len1 + oriEvent.Clock); */ OtoArgs oa = new OtoArgs(); if (vdb != null) { int CheckNote = oriEvent.ID.Note; if (oriEvent.UstEvent != null) { CheckNote = oriEvent.UstEvent.ReplaceNoteID > 0 ? oriEvent.UstEvent.ReplaceNoteID : oriEvent.ID.Note; } oa = vdb.attachFileNameFromLyric(PRO.Split(',')[1], CheckNote); } if (oa.fileName == null || (oa.fileName != null && oa.fileName == "")) { oriEvent.ID.LyricHandle.L0.setPhoneticSymbol(PRO.Split(',')[0]); //oriEvent.UstEvent.setVoiceOverlap(oriEvent.UstEvent.getVoiceOverlap() + preover); dstVibstrBrustEvents.Add(oriEvent, oriVibstrBrustEvents); dstPitchBrust.Add(oriEvent, oriPitchBrust); dstParentTable.Add(oriEvent, oriEvent); return; } int SplitLen = (int)oriEvent.UstEvent.SplitLength; if (oriEvent.UstEvent.SplitisPercent) { SplitLen = (int)(oriEvent.ID.getLength() * SplitLen / 100.0); } float V2PreUttr = oa.msPreUtterance + oriEvent.UstEvent.SplitSTP; float V1PreUttr = oriEvent.UstEvent.getPreUtterance() + oriEvent.UstEvent.getStartPoint(); int RealV1Start = (int)mVsq.getClockFromSec(mVsq.getSecFromClock(oriEvent.Clock) - V1PreUttr / 1000.0); int RealV2Start = (int)mVsq.getClockFromSec(mVsq.getSecFromClock(oriEvent.Clock + Len1) - V2PreUttr / 1000.0); int R = Cell5(RealV2Start - RealV1Start); int Dert = (RealV2Start - RealV1Start) - R; if (Dert > 3) { Len1 = Len1 + ((5 - Dert) > 0 ? (5 - Dert) : 0); } else { Len1 = Len1 - Dert; } Len2 = oriEvent.ID.getLength() - Len1; SplitTime = (Len1 + oriEvent.Clock); int CrossLen = (int)((oa.msOverlap) + oriEvent.UstEvent.SplitVoiceOverlap); VsqEvent V1 = (VsqEvent)oriEvent.clone(); V1.ID.LyricHandle.L0.setPhoneticSymbol(PRO.Split(',')[0]); V1.Clock = oriEvent.Clock; V1.ID.setLength(Len1); V1.UstEvent.setVoiceOverlap(V1.UstEvent.getVoiceOverlap() + V1.UstEvent.NotePreOverlap); UstEnvelope env = oriEvent.UstEvent.getEnvelope(); if (env == null) { env = new UstEnvelope(); } env.p3 = CrossLen; env.p4 = 0; env.v4 = 0; V1.UstEvent.setEnvelope(env); VsqEvent V2 = (VsqEvent)oriEvent.clone(); V2.ID.LyricHandle.L0.setPhoneticSymbol(PRO.Split(',')[1]); V2.Clock = SplitTime; V2.ID.setLength(Len2); V2.UstEvent.setVoiceOverlap(CrossLen); V2.UstEvent.setPreUtterance(oa.msPreUtterance); V2.UstEvent.setStartPoint(V2.UstEvent.SplitSTP); V2.UstEvent.LeftLimit = 0; env = oriEvent.UstEvent.getEnvelope(); if (env == null) { env = new UstEnvelope(); } env.p2 = CrossLen; env.v2 = env.v2 - V1.UstEvent.MoreOver; if (env.v2 < 0) { env.v2 = 0; } env.p1 = 0; env.v1 = 0; if (env.p5 > 0) { env.p5 = env.p5 - Len1; } V2.UstEvent.setEnvelope(env); dstVibstrBrustEvents.Add(V1, oriVibstrBrustEvents); dstPitchBrust.Add(V1, oriPitchBrust); dstParentTable.Add(V1, oriEvent); dstVibstrBrustEvents.Add(V2, oriVibstrBrustEvents); dstPitchBrust.Add(V2, oriPitchBrust); dstParentTable.Add(V2, oriEvent); } else { if (oriEvent.ID.LyricHandle.L0.getPhoneticSymbol().IndexOf(",") > 0) { oriEvent.ID.LyricHandle.L0.setPhoneticSymbol(PRO.Split(',')[0]); } dstVibstrBrustEvents.Add(oriEvent, oriVibstrBrustEvents); oriEvent.UstEvent.setVoiceOverlap(oriEvent.UstEvent.getVoiceOverlap() + oriEvent.UstEvent.NotePreOverlap); dstPitchBrust.Add(oriEvent, oriPitchBrust); dstParentTable.Add(oriEvent, oriEvent); } } else { dstVibstrBrustEvents.Add(oriEvent, oriVibstrBrustEvents); oriEvent.UstEvent.setVoiceOverlap(oriEvent.UstEvent.getVoiceOverlap() + oriEvent.UstEvent.NotePreOverlap); dstPitchBrust.Add(oriEvent, oriPitchBrust); dstParentTable.Add(oriEvent, oriEvent); } }