public VibratoPointIteratorBySec(VsqFileEx vsq, VibratoBPList rate, int start_rate, VibratoBPList depth, int start_depth, int clock_start, int clock_width, float sec_resolution) { this.vsq = vsq; this.rate = rate; this.start_rate = start_rate; this.depth = depth; this.start_depth = start_depth; this.clock_start = clock_start; this.clock_width = clock_width; this.sec_resolution = sec_resolution; sec0 = vsq.getSecFromClock(clock_start); sec1 = vsq.getSecFromClock(clock_start + clock_width); count = (int)((sec1 - sec0) / sec_resolution); phase = 0; start_rate = rate.getValue(0.0f, start_rate); start_depth = depth.getValue(0.0f, start_depth); amplitude = start_depth * 2.5f / 127.0f / 2.0f; // ビブラートの振幅。 period = getPeriodFromRate(start_rate); //ビブラートの周期、秒 omega = (float)(2.0 * Math.PI / period); // 角速度(rad/sec) sec = sec0; fadewidth = (float)(sec1 - sec0) * 0.2f; }
/// <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(); }
/// <summary> /// 初期化メソッド /// </summary> /// <param name="parameter"></param> public void init(VsqFileEx vsq, int track, int start_clock, int end_clock, int sample_rate) { getDriver().setSampleRate(sample_rate); mTrack = track; mStartClock = start_clock; mEndClock = end_clock; mSampleRate = sample_rate; this.mVsq = (VsqFileEx)vsq.clone(); this.mVsq.updateTotalClocks(); if (mEndClock < this.mVsq.TotalClocks) { this.mVsq.removePart(mEndClock, this.mVsq.TotalClocks + 480); } double end_sec = mVsq.getSecFromClock(start_clock); double start_sec = mVsq.getSecFromClock(end_clock); double trim_sec = 0.0; // レンダリング結果から省かなければならない秒数。 if (mStartClock < this.mVsq.getPreMeasureClocks()) { trim_sec = this.mVsq.getSecFromClock(mStartClock); } else { this.mVsq.removePart(mVsq.getPreMeasureClocks(), mStartClock); trim_sec = this.mVsq.getSecFromClock(this.mVsq.getPreMeasureClocks()); } this.mVsq.updateTotalClocks(); mTrimRemain = (int)(trim_sec * mSampleRate); //mTrimRemain = 0; #if DEBUG sout.println("AeuqsToneWaveGenerator#init; mTrimRemain=" + mTrimRemain); #endif }
public void begin(long total_samples, WorkerState state) { is_running_ = true; total_samples_ = total_samples; int buffer_length = sample_rate_ / 10; double[] left = new double[buffer_length]; double[] right = new double[buffer_length]; if (driver_.getUi(null) == null) { throw new InvalidOperationException("plugin ui を main view のスレッドで作成した後、このメソッドを呼ばなくてはならない。"); } var eventQueue = generateMidiEvent(sequence_, track_index_); foreach (var sequence_item in eventQueue.getSequence()) { var clock = sequence_item.Key; var queue = sequence_item.Value; long to_sample = (long)(sequence_.getSecFromClock(clock) * sample_rate_); if (to_sample >= total_samples_) { to_sample = total_samples_; } doSynthesis(to_sample, left, right, state); if (position_ >= total_samples_) { break; } // noteOff, noteOn の順に分けて send する方法も考えられるが、正しく動作しない。 // このため、いったん一つの配列にまとめてから send する必要がある。 var events = new List <MidiEvent>(); events.AddRange(queue.pit); events.AddRange(queue.noteoff); events.AddRange(queue.noteon); driver_.send(events.ToArray()); //TODO: のこりのイベント送る処理 } doSynthesis(total_samples, left, right, state); receiver_.end(); is_running_ = false; state.reportComplete(); }
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); } } } }
/// <summary> /// 初期化メソッド /// </summary> /// <param name="parameter"></param> public void init( VsqFileEx vsq, int track, int start_clock, int end_clock, int sample_rate ) { getDriver().setSampleRate( sample_rate ); mTrack = track; mStartClock = start_clock; mEndClock = end_clock; mSampleRate = sample_rate; this.mVsq = (VsqFileEx)vsq.clone(); this.mVsq.updateTotalClocks(); if ( mEndClock < this.mVsq.TotalClocks ) { this.mVsq.removePart( mEndClock, this.mVsq.TotalClocks + 480 ); } double end_sec = mVsq.getSecFromClock( start_clock ); double start_sec = mVsq.getSecFromClock( end_clock ); double trim_sec = 0.0; // レンダリング結果から省かなければならない秒数。 if ( mStartClock < this.mVsq.getPreMeasureClocks() ) { trim_sec = this.mVsq.getSecFromClock( mStartClock ); } else { this.mVsq.removePart( mVsq.getPreMeasureClocks(), mStartClock ); trim_sec = this.mVsq.getSecFromClock( this.mVsq.getPreMeasureClocks() ); } this.mVsq.updateTotalClocks(); mTrimRemain = (int)(trim_sec * mSampleRate); //mTrimRemain = 0; #if DEBUG sout.println( "AeuqsToneWaveGenerator#init; mTrimRemain=" + mTrimRemain ); #endif }
/*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); } }
/// <summary> /// /// </summary> /// <param name="vsq"></param> /// <param name="track"></param> /// <param name="clock_start"></param> /// <param name="clock_end"></param> /// <returns></returns> private TreeMap<Integer, MidiEventQueue> generateMidiEvent( VsqFileEx vsq, int track, int clock_start, int clock_end ) { TreeMap<Integer, MidiEventQueue> list = new TreeMap<Integer, MidiEventQueue>(); VsqTrack t = vsq.Track.get( track ); // 歌手変更 for ( Iterator<VsqEvent> itr = t.getSingerEventIterator(); itr.hasNext(); ) { VsqEvent item = itr.next(); if ( clock_start <= item.Clock && item.Clock <= clock_end ) { if ( item.ID.IconHandle == null ) { continue; } int program = item.ID.IconHandle.Program; if ( 0 > program || program >= AquesToneDriver.SINGERS.Length ) { program = 0; } ParameterEvent singer = new ParameterEvent(); singer.index = mDriver.phontParameterIndex; singer.value = program + 0.01f; if ( !list.containsKey( item.Clock ) ) { list.put( item.Clock, new MidiEventQueue() ); } MidiEventQueue queue = list.get( item.Clock ); if ( queue.param == null ) { queue.param = new Vector<ParameterEvent>(); } queue.param.add( singer ); } else if ( clock_end < item.Clock ) { break; } } // ノート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イベントを作成 String lyric = item.ID.LyricHandle.L0.Phrase; String katakana = KanaDeRomanization.hiragana2katakana( KanaDeRomanization.Attach( lyric ) ); int index = -1; for ( int i = 0; i < AquesToneDriver.PHONES.Length; i++ ) { if ( katakana.Equals( AquesToneDriver.PHONES[i] ) ) { index = i; break; } } if ( index >= 0 ) { if ( !list.containsKey( item.Clock ) ) { list.put( item.Clock, new MidiEventQueue() ); } MidiEventQueue queue = list.get( item.Clock ); if ( queue.noteon == null ) { queue.noteon = new Vector<MidiEvent>(); } // index行目に移動するコマンドを贈る MidiEvent moveline = new MidiEvent(); moveline.firstByte = 0xb0; moveline.data = new[] { 0x0a, index }; MidiEvent noteon = new MidiEvent(); noteon.firstByte = 0x90; noteon.data = new int[] { item.ID.Note, item.ID.Dynamics }; Vector<MidiEvent> add = Arrays.asList( new MidiEvent[] { moveline, noteon } ); queue.noteon.addAll( add ); pit_send.add( new Point( item.Clock, item.Clock ) ); } /* 音符頭で設定するパラメータ */ // Release MidiEventQueue q = null; if ( !list.containsKey( item.Clock ) ) { q = new MidiEventQueue(); } else { q = list.get( item.Clock ); } if ( q.param == null ) { q.param = new Vector<ParameterEvent>(); } String strRelease = VsqFileEx.getEventTag( item, VsqFileEx.TAG_VSQEVENT_AQUESTONE_RELEASE ); int release = 64; try { release = str.toi( 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 ); if ( !list.containsKey( item.Clock ) ) { list.put( item.Clock, new MidiEventQueue() ); } MidiEventQueue queue = list.get( item.Clock ); if ( queue.pit == null ) { queue.pit = new Vector<MidiEvent>(); } else { 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; if ( queue.param == null ) { queue.param = new Vector<ParameterEvent>(); } 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; } if ( !list.containsKey( item.Clock ) ) { list.put( item.Clock, new MidiEventQueue() ); } MidiEventQueue queue = list.get( item.Clock ); ParameterEvent pe = new ParameterEvent(); pe.index = mDriver.bendLblParameterIndex; pe.value = required_pbs / 13.0f; if ( queue.param == null ) { queue.param = new Vector<ParameterEvent>(); } 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); if ( !list.containsKey( clock ) ) { list.put( clock, new MidiEventQueue() ); } MidiEventQueue q = list.get( clock ); MidiEvent me = getPitMidiEvent( pit_value ); if ( q.pit == null ) { q.pit = new Vector<MidiEvent>(); } else { 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 } ); if ( !list.containsKey( endclock ) ) { list.put( endclock, new MidiEventQueue() ); } MidiEventQueue q = list.get( endclock ); if ( q.noteoff == null ) { q.noteoff = new Vector<MidiEvent>(); } 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 = null; if ( list.containsKey( clock ) ) { queue = list.get( clock ); } else { queue = new MidiEventQueue(); } if ( queue.param == null ) { queue.param = new Vector<ParameterEvent>(); } queue.param.add( pbse ); list.put( clock, queue ); } 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 = null; if ( list.containsKey( clock ) ) { queue = list.get( clock ); } else { queue = new MidiEventQueue(); } if ( queue.pit == null ) { queue.pit = new Vector<MidiEvent>(); } else { queue.pit.clear(); } queue.pit.add( pbs0 ); list.put( clock, queue ); } else if ( clock_end < clock ) { break; } } } appendParameterEvents( list, dyn, mDriver.volumeParameterIndex, clock_start, clock_end ); appendParameterEvents( list, bre, mDriver.haskyParameterIndex, clock_start, clock_end ); appendParameterEvents( list, cle, mDriver.resonancParameterIndex, clock_start, clock_end ); appendParameterEvents( list, por, mDriver.portaTimeParameterIndex, clock_start, clock_end ); return list; }
/// <summary> /// 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 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 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; }
private static void ThreadProc() { const int TOLERANCE_MILLISEC = 10; while (!m_stop_required) { if (s_queue.size() == 0) { Thread.Sleep(100); continue; } int clock = s_queue.get(0).Clock; double tick_sec = m_vsq.getSecFromClock(clock); double next_tick = m_started + ((tick_sec - m_started_sec) / m_speed); double now = PortUtil.getCurrentTime(); double time_span = next_tick - now; if (time_span <= 0) { Vector <MidiQueue> add = new Vector <MidiQueue>(); while (s_queue.size() > 0 && s_queue.get(0).Clock == clock) { if (s_queue.get(0).Done != null) { add.addAll(s_queue.get(0).Done(s_queue.get(0))); } MidiQueue item = s_queue.get(0); if (item.Track == 0 || s_metronome_device == s_general_device) { s_device0.Play(item.Channel, item.Program, item.Note, item.Velocity); } else { s_device1.Play(item.Channel, item.Program, item.Note, item.Velocity); } s_queue.removeElementAt(0); } s_queue.addAll(add); Collections.sort(s_queue); continue; } int wait_millisec = (int)((next_tick - PortUtil.getCurrentTime()) * 1000.0) - PreUtterance; int thiswait = (wait_millisec > TOLERANCE_MILLISEC * 2) ? TOLERANCE_MILLISEC * 2 : wait_millisec; #if DEBUG AppManager.debugWriteLine("MidiPlayer#ThreadProc; wait_millisec=" + wait_millisec); #endif while (thiswait > TOLERANCE_MILLISEC) { Thread.Sleep(thiswait); wait_millisec = (int)((next_tick - PortUtil.getCurrentTime()) * 1000.0) - PreUtterance; if (wait_millisec < TOLERANCE_MILLISEC || m_stop_required) { break; } thiswait = wait_millisec; } if (m_stop_required) { break; } if (m_temp_exit) { m_temp_exit = false; Vector <MidiQueue> add = new Vector <MidiQueue>(); while (s_queue.size() > 0 && s_queue.get(0).Clock == clock) { if (s_queue.get(0).Done != null) { add.addAll(s_queue.get(0).Done(s_queue.get(0))); } s_queue.removeElementAt(0); } s_queue.addAll(add); Collections.sort(s_queue); continue; } Vector <MidiQueue> adding = new Vector <MidiQueue>(); while (s_queue.size() > 0 && s_queue.get(0).Clock == clock) { if (s_queue.get(0).Track == 0 || s_metronome_device == s_general_device) { if (s_queue.get(0).Track != 0 || (s_queue.get(0).Track == 0 && !m_stop_metronome_required)) { s_device0.Play(s_queue.get(0).Channel, s_queue.get(0).Program, s_queue.get(0).Note, s_queue.get(0).Velocity); } } else { s_device1.Play(s_queue.get(0).Channel, s_queue.get(0).Program, s_queue.get(0).Note, s_queue.get(0).Velocity); } if (s_queue.get(0).Done != null) { if (s_queue.get(0).Track != 0 || (s_queue.get(0).Track == 0 && !m_stop_metronome_required)) { adding.addAll(s_queue.get(0).Done(s_queue.get(0))); } } s_queue.removeElementAt(0); } s_queue.addAll(adding); Collections.sort(s_queue); } }
/// <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); }