/// <summary> /// Perform channel swapping while exporting to a file. /// </summary> void ExportProcess(string path) { int channels = reader.ChannelCount; int[] targetIndexes = new int[channels]; for (int i = 0; i < channels; ++i) { targetIndexes[i] = -1; for (int j = 0; j < channels; ++j) { if ((ReferenceChannel)sourceChannels.Items[i] == (ReferenceChannel)targetChannels.Items[j]) { targetIndexes[i] = j; } } } using RIFFWaveWriter writer = new(path, channels, reader.Length, reader.SampleRate, reader.Bits); reader.Reset(); writer.WriteHeader(); long position = 0, end = channels * reader.Length; float[] source = new float[channels * reader.SampleRate], target = new float[source.Length]; while (position < end) { long stepSize = Math.Min(source.Length, end - position); reader.ReadBlock(source, 0, stepSize); Array.Clear(target, 0, (int)stepSize); for (int ch = 0; ch < channels; ++ch) { int targetIndex = targetIndexes[ch]; if (targetIndex == -1) { continue; } for (int sample = ch, pair = targetIndex; sample < source.Length; sample += channels, pair += channels) { target[pair] = source[sample]; } } writer.WriteBlock(target, 0, stepSize); position += stepSize; double progress = position / (double)end; process.UpdateStatusLazy($"Exporting... ({progress:0.00%})"); process.UpdateProgressBar(progress); } process.UpdateStatus("Finished!"); process.UpdateProgressBar(1); }
/// <summary> /// Expand the entire filesystem in the background. /// </summary> public void ExpandAll() { for (int i = 0, c = Items.Count; i < c; ++i) { double progress = i / (double)c; taskEngine.UpdateProgressBar(progress); taskEngine.UpdateStatusLazy(string.Format("Expanding folder {0} of {1} ({2})...", i + 1, c, progress.ToString("0.00%"))); ((FilesystemItem)Items[i]).Dispatcher.Invoke(() => ((FilesystemItem)Items[i]).ExpandSubtree()); } taskEngine.UpdateProgressBar(1); taskEngine.UpdateStatus("All folders expanded."); }
/// <summary> /// Renders a listener to a file, and returns some measurements of the render. /// </summary> public static RenderStats WriteRender(Listener listener, Track target, AudioWriter writer, TaskEngine taskEngine, bool dynamicOnly, bool heightOnly) { RenderStats stats = new(listener); const long updateInterval = 50000; long rendered = 0, untilUpdate = updateInterval; double samplesToProgress = 1.0 / target.Length, samplesToSeconds = 1.0 / listener.SampleRate; bool customMuting = dynamicOnly || heightOnly; DateTime start = DateTime.Now; while (rendered < target.Length) { float[] result = listener.Render(); #if DEBUG if (rendered > 2500000 && WaveformUtils.GetPeakSigned(result) > .5f) { ; // TODO: debug, Amaze will follow with a heavy gain frame and then a normal frame after this detection } #endif if (target.Length - rendered < listener.UpdateRate) { Array.Resize(ref result, (int)(target.Length - rendered)); } if (writer != null) { writer.WriteBlock(result, 0, result.LongLength); } if (rendered > firstFrame) { stats.Update(); } if (customMuting) { IReadOnlyList <Source> objects = target.Renderer.Objects; for (int i = 0, c = objects.Count; i < c; ++i) { Vector3 rawPos = objects[i].Position / Listener.EnvironmentSize; objects[i].Mute = (dynamicOnly && MathF.Abs(rawPos.X) % 1 < .01f && MathF.Abs(rawPos.Y) % 1 < .01f && MathF.Abs(rawPos.Z % 1) < .01f) || (heightOnly && rawPos.Y == 0); } } rendered += listener.UpdateRate; if ((untilUpdate -= listener.UpdateRate) <= 0) { double progress = rendered * samplesToProgress; double speed = rendered * samplesToSeconds / (DateTime.Now - start).TotalSeconds; taskEngine.UpdateStatusLazy($"Rendering... ({progress:0.00%}, speed: {speed:0.00}x)"); taskEngine.UpdateProgressBar(progress); untilUpdate = updateInterval; } } if (writer != null) { writer.Dispose(); } return(stats); }