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(); }