void Resample(RenderItem item) { byte[] data = null; try { uint hash = item.HashParameters(); data = cache.Get(hash); if (data == null) { CopySourceTemp(item); if (!resamplers.TryGetValue(item.ResamplerName, out var driver)) { driver = this.driver; } data = driver.DoResampler(DriverModels.CreateInputModel(item, 0), Log.Logger); if (data == null || data.Length == 0) { throw new Exception("Empty render result."); } cache.Put(hash, data); Log.Information($"Sound {hash:x} {item.Oto.Alias} {item.GetResamplerExeArgs()} resampled."); CopyBackMetaFiles(item); } } catch (Exception e) { Log.Error(e, $"Failed to render item {item.SourceFile} {item.Oto.Alias} {item.GetResamplerExeArgs()}."); } finally { item.Data = data ?? new byte[0]; item.OnComplete?.Invoke(item.Data); item.progress?.CompleteOne($"Resampling \"{item.phonemeName}\""); } }
void CopyBackMetaFiles(RenderItem item) { string sourceTemp = item.SourceTemp; var metaFiles = GetMetaFiles(item.SourceFile, item.SourceTemp); metaFiles.ForEach(t => CopyOrStamp(t.Item2, t.Item1)); }
private RenderItem BuildRenderItem(UPhoneme phoneme, UVoicePart part, UProject project) { USinger singer = project.Tracks[part.TrackNo].Singer; string rawfile = Lib.EncodingUtil.ConvertEncoding(singer.FileEncoding, singer.PathEncoding, phoneme.Oto.File); rawfile = Path.Combine(singer.Path, rawfile); double strechRatio = Math.Pow(2, 1.0 - (double)(int)phoneme.Parent.Expressions["velocity"].Data / 100); double length = phoneme.Oto.Preutter * strechRatio + phoneme.Envelope.Points[4].X; double requiredLength = Math.Ceiling(length / 50 + 1) * 50; double lengthAdjustment = phoneme.TailIntrude == 0 ? phoneme.Preutter : phoneme.Preutter - phoneme.TailIntrude + phoneme.TailOverlap; RenderItem item = new RenderItem() { // For resampler RawFile = rawfile, NoteNum = phoneme.Parent.NoteNum, Velocity = (int)phoneme.Parent.Expressions["velocity"].Data, Volume = (int)phoneme.Parent.Expressions["volume"].Data, StrFlags = phoneme.Parent.GetResamplerFlags(), PitchData = BuildPitchData(phoneme, part, project), RequiredLength = (int)requiredLength, Oto = phoneme.Oto, Tempo = project.BPM, // For connector SkipOver = phoneme.Oto.Preutter * strechRatio - phoneme.Preutter, PosMs = project.TickToMillisecond(part.PosTick + phoneme.Parent.PosTick + phoneme.PosTick) - phoneme.Preutter, DurMs = project.TickToMillisecond(phoneme.DurTick) + lengthAdjustment, Envelope = phoneme.Envelope.Points }; return(item); }
async Task <SequencingSampleProvider> RenderPartAsync(UVoicePart part, UProject project, string cacheDir) { var singer = project.Tracks[part.TrackNo].Singer; if (singer == null || !singer.Loaded) { return(null); } var tasks = new List <Task <RenderItem> >(); var progress = new Progress(part.Notes.Sum(note => note.Phonemes.Count)); progress.Clear(); foreach (var note in part.Notes) { foreach (var phoneme in note.Phonemes) { if (string.IsNullOrEmpty(phoneme.Oto.File)) { Log.Warning($"Cannot find phoneme in note {note.Lyric}"); continue; } var item = new RenderItem(phoneme, part, project); item.progress = progress; tasks.Add(Task <RenderItem> .Factory.StartNew(ResamplePhonemeAsync, item, cancellationTokenSource.Token)); } } await Task.WhenAll(tasks.ToArray()); progress.Clear(); return(new SequencingSampleProvider(tasks.Select(task => new RenderItemSampleProvider(task.Result)))); }
RenderItem ResamplePhonemeAsync(object state) { RenderItem item = state as RenderItem; Log.Verbose($"Sound {item.HashParameters():x} resampling {item.GetResamplerExeArgs()}"); var output = driver.DoResampler(DriverModels.CreateInputModel(item, 0)); item.Sound = MemorySampleProvider.FromStream(output); output.Dispose(); item.progress.CompleteOne($"Resampling \"{item.phonemeName}\""); return(item); }
public RenderItemSampleProvider(RenderItem renderItem) { this.RenderItem = renderItem; var cachedSampleProvider = new CachedSoundSampleProvider(RenderItem.Sound); var offsetSampleProvider = new OffsetSampleProvider(new EnvelopeSampleProvider(cachedSampleProvider, RenderItem.Envelope, RenderItem.SkipOver)) { DelayBySamples = (int)(RenderItem.PosMs * cachedSampleProvider.WaveFormat.SampleRate / 1000), TakeSamples = (int)(RenderItem.DurMs * cachedSampleProvider.WaveFormat.SampleRate / 1000), SkipOverSamples = (int)(RenderItem.SkipOver * cachedSampleProvider.WaveFormat.SampleRate / 1000) }; this.signalChain = offsetSampleProvider; this.firstSample = offsetSampleProvider.DelayBySamples + offsetSampleProvider.SkipOverSamples; this.lastSample = this.firstSample + offsetSampleProvider.TakeSamples; }
private List <RenderItem> RenderAsync(UVoicePart part, UProject project, IResamplerDriver engine, BackgroundWorker worker) { var renderItems = new List <RenderItem>(); var watch = new Stopwatch(); watch.Start(); Log.Information("Resampling start."); lock (part) { var cacheDir = PathManager.Inst.GetCachePath(project.FilePath); var cacheFiles = Directory.EnumerateFiles(cacheDir).ToArray(); int count = 0, i = 0; foreach (var note in part.Notes) { foreach (var phoneme in note.Phonemes) { count++; } } foreach (var note in part.Notes) { foreach (var phoneme in note.Phonemes) { if (string.IsNullOrEmpty(phoneme.Oto.File)) { Log.Warning($"Cannot find phoneme in note {note.Lyric}"); continue; } var item = new RenderItem(phoneme, part, project); //System.Diagnostics.Debug.WriteLine("Sound {0:x} resampling {1}", item.HashParameters(), item.GetResamplerExeArgs()); var engineArgs = DriverModels.CreateInputModel(item, 0); var output = engine.DoResampler(engineArgs); item.Sound = MemorySampleProvider.FromStream(output); output.Dispose(); renderItems.Add(item); worker.ReportProgress(100 * ++i / count, $"Resampling \"{phoneme.Phoneme}\" {i}/{count}"); } } } watch.Stop(); Log.Information($"Resampling end, total time {watch.Elapsed}"); return(renderItems); }
RenderItem ResamplePhonemeAsync(object state) { RenderItem item = state as RenderItem; uint hash = item.HashParameters(); byte[] data = cache.Get(hash); if (data == null) { data = driver.DoResampler(DriverModels.CreateInputModel(item, 0)); cache.Put(hash, data); Log.Information($"Sound {hash:x} {item.GetResamplerExeArgs()} resampled."); } else { Log.Information($"Sound {hash:x} {item.GetResamplerExeArgs()} cache retrieved."); } var stream = new MemoryStream(data); item.Sound = MemorySampleProvider.FromStream(stream); item.progress.CompleteOne($"Resampling \"{item.phonemeName}\""); return(item); }
private List <RenderItem> RenderAsync(UVoicePart part, UProject project, IResamplerDriver engine, BackgroundWorker worker) { List <RenderItem> renderItems = new List <RenderItem>(); System.Diagnostics.Stopwatch watch = new Stopwatch(); watch.Start(); System.Diagnostics.Debug.WriteLine("Resampling start"); lock (part) { string cacheDir = PathManager.Inst.GetCachePath(project.FilePath); string[] cacheFiles = Directory.EnumerateFiles(cacheDir).ToArray(); int count = 0, i = 0; foreach (UNote note in part.Notes) { foreach (UPhoneme phoneme in note.Phonemes) { count++; } } foreach (UNote note in part.Notes) { foreach (UPhoneme phoneme in note.Phonemes) { RenderItem item = BuildRenderItem(phoneme, part, project); var sound = RenderCache.Inst.Get(item.HashParameters()); if (sound == null) { string cachefile = Path.Combine(cacheDir, string.Format("{0:x}.wav", item.HashParameters())); if (!cacheFiles.Contains(cachefile)) { System.Diagnostics.Debug.WriteLine("Sound {0:x} resampling {1}", item.HashParameters(), item.GetResamplerExeArgs()); DriverModels.EngineInput engineArgs = DriverModels.CreateInputModel(item, 0); System.IO.Stream output = engine.DoResampler(engineArgs); sound = new CachedSound(output); } else { System.Diagnostics.Debug.WriteLine("Sound {0:x} found on disk {1}", item.HashParameters(), item.GetResamplerExeArgs()); sound = new CachedSound(cachefile); } RenderCache.Inst.Put(item.HashParameters(), sound, engine.GetInfo().ToString()); } else { System.Diagnostics.Debug.WriteLine("Sound {0} found in cache {1}", item.HashParameters(), item.GetResamplerExeArgs()); } item.Sound = sound; renderItems.Add(item); worker.ReportProgress(100 * ++i / count, string.Format("Resampling \"{0}\" {1}/{2}", phoneme.Phoneme, i, count)); } } } watch.Stop(); System.Diagnostics.Debug.WriteLine("Resampling end"); System.Diagnostics.Debug.WriteLine("Total cache size {0:n0} bytes", RenderCache.Inst.TotalMemSize); System.Diagnostics.Debug.WriteLine("Total time {0} ms", watch.Elapsed.TotalMilliseconds); return(renderItems); }
/// <summary> /// 从RenderItem初始化过程 /// </summary> /// <returns></returns> internal static EngineInput CreateInputModel(RenderItem renderItem,double Modulation) { EngineInput Ret = new EngineInput(); Ret.inputWaveFile = renderItem.RawFile; Ret.NoteString = MusicMath.GetNoteString(renderItem.NoteNum); Ret.Velocity = renderItem.Velocity; Ret.StrFlags = renderItem.StrFlags; Ret.Offset = renderItem.Oto.Offset; Ret.RequiredLength = renderItem.RequiredLength; Ret.Consonant = renderItem.Oto.Consonant; Ret.Cutoff = renderItem.Oto.Cutoff; Ret.Volume = renderItem.Volume; Ret.Modulation = Modulation; Ret.pitchBend = renderItem.PitchData.ToArray(); Ret.nPitchBend = renderItem.PitchData.Count; Ret.Tempo = renderItem.Tempo; return Ret; }
private RenderItem BuildRenderItem(UPhoneme phoneme, UVoicePart part, UProject project) { USinger singer = project.Tracks[part.TrackNo].Singer; string rawfile = Lib.EncodingUtil.ConvertEncoding(singer.FileEncoding, singer.PathEncoding, phoneme.Oto.File); rawfile = Path.Combine(singer.Path, rawfile); double strechRatio = Math.Pow(2, 1.0 - (double)(int)phoneme.Parent.Expressions["velocity"].Data / 100); double length = phoneme.Oto.Preutter * strechRatio + phoneme.Envelope.Points[4].X; double requiredLength = Math.Ceiling(length / 50 + 1) * 50; double lengthAdjustment = phoneme.TailIntrude == 0 ? phoneme.Preutter : phoneme.Preutter - phoneme.TailIntrude + phoneme.TailOverlap; RenderItem item = new RenderItem() { // For resampler RawFile = rawfile, NoteNum = phoneme.Parent.NoteNum, Velocity = (int)phoneme.Parent.Expressions["velocity"].Data, Volume = (int)phoneme.Parent.Expressions["volume"].Data, StrFlags = phoneme.Parent.GetResamplerFlags(), PitchData = BuildPitchData(phoneme, part, project), RequiredLength = (int)requiredLength, Oto = phoneme.Oto, Tempo = project.BPM, // For connector SkipOver = phoneme.Oto.Preutter * strechRatio - phoneme.Preutter, PosMs = project.TickToMillisecond(part.PosTick + phoneme.Parent.PosTick + phoneme.PosTick) - phoneme.Preutter, DurMs = project.TickToMillisecond(phoneme.DurTick) + lengthAdjustment, Envelope = phoneme.Envelope.Points }; return item; }