Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions OpenUtau.Core/Classic/ExeResampler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,11 @@
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using NAudio.Wave;
using OpenUtau.Core;
using OpenUtau.Core.Format;
using OpenUtau.Core.Util;
using OpenUtau.Core.Ustx;
using Serilog;

namespace OpenUtau.Classic {
Expand Down Expand Up @@ -102,10 +100,17 @@ public string DoResamplerReturnsFile(ResamplerItem args, ILogger logger) {
string ArgParam = FormattableString.Invariant(
$"\"{args.inputTemp}\" \"{tmpFile}\" {MusicMath.GetToneName(args.tone)} {args.velocity} \"{args.GetFlagsString()}\" {args.offset} {args.durRequired} {args.consonant} {args.cutoff} {args.volume} {args.modulation} !{args.tempo} {Base64.Base64EncodeInt12(args.pitches)}");
logger.Information($" > [thread-{threadId}] {FilePath} {ArgParam}");
string resamplerOutput;
if (useWine) {
ProcessRunner.Run(winePath, $"{FilePath} {ArgParam}", logger);
resamplerOutput = ProcessRunner.Run(winePath, $"{FilePath} {ArgParam}", logger);
} else {
ProcessRunner.Run(FilePath, ArgParam, logger);
resamplerOutput = ProcessRunner.Run(FilePath, ArgParam, logger);
}
// check if the file has been created
if (!File.Exists(tmpFile)) {
throw new Core.Render.ResamplerFailedException(
$" > [thread-{threadId}]\n{resamplerOutput}"
);
}
return tmpFile;
}
Expand Down
3 changes: 3 additions & 0 deletions OpenUtau.Core/Render/IRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
namespace OpenUtau.Core.Render {
public class NoResamplerException : Exception { }
public class NoWavtoolException : Exception { }
public class ResamplerFailedException : Exception {
public ResamplerFailedException(string message) : base(message) {}
}

/// <summary>
/// Render result of a phrase.
Expand Down
3 changes: 3 additions & 0 deletions OpenUtau.Core/Render/RenderEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,9 @@ public Tuple<WaveMix, List<Fader>> RenderMixdown(TaskScheduler uiScheduler, ref
} else if (innerEx.Any(e => e is DllNotFoundException)) {
DocManager.Inst.ExecuteCmd(new ErrorMessageNotification(
new MessageCustomizableException("Failed to render.", "<translate:errors.failed.render>: <translate:errors.install.cpp>", flatEx)));
} else if (innerEx.Any(e => e is ResamplerFailedException)) {
DocManager.Inst.ExecuteCmd(new ErrorMessageNotification(
new MessageCustomizableException("Failed to render.", "<translate:errors.resampler.failed.message>", flatEx)));
} else {
DocManager.Inst.ExecuteCmd(new ErrorMessageNotification(
new MessageCustomizableException("Failed to render.", "<translate:errors.failed.render>", flatEx)));
Expand Down
75 changes: 56 additions & 19 deletions OpenUtau.Core/Util/ProcessRunner.cs
Original file line number Diff line number Diff line change
@@ -1,57 +1,94 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading;
using Serilog;

namespace OpenUtau.Core.Util {
public static class ProcessRunner {
public static bool DebugSwitch { get; set; }
public static void Run(string file, string args, ILogger logger, string workDir = null, int timeoutMs = 60000) {
public static string Run(string file, string args, ILogger logger, string workDir = null, int timeoutMs = 60000) {
if (!File.Exists(file)) {
throw new FileNotFoundException($"Executable {file} not found.");
}
var threadId = Thread.CurrentThread.ManagedThreadId;
var output = new StringBuilder();
var outputLock = new object();

// Signals used to ensure the async stdout/stderr readers have flushed all data before we read `output`.
using var stdoutDone = new ManualResetEventSlim(false);
using var stderrDone = new ManualResetEventSlim(false);
using (var proc = new Process()) {
proc.StartInfo = new ProcessStartInfo(file, args) {
Environment = {{"LANG", "ja_JP.utf8"}},
Environment = { { "LANG", "ja_JP.utf8" } },
UseShellExecute = false,
RedirectStandardOutput = DebugSwitch,
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true,
WorkingDirectory = workDir,
};
if (DebugSwitch) {
proc.OutputDataReceived += (o, e) => {
if (!string.IsNullOrEmpty(e.Data)) {
logger.Information($"ProcessRunner >>> [thread-{threadId}] {e.Data}");
}
};
}

proc.OutputDataReceived += (o, e) => {
if (e.Data == null) {
stdoutDone.Set();
return;
}
if (DebugSwitch) {
logger.Information($"ProcessRunner >>> [thread-{threadId}] {e.Data}");
}
lock (outputLock) {
output.AppendLine(e.Data);
}
};
proc.ErrorDataReceived += (o, e) => {
if (!string.IsNullOrEmpty(e.Data)) {
logger.Error($"ProcessRunner >>> [thread-{threadId}] {e.Data}");
if (e.Data == null) {
stderrDone.Set();
return;
}
logger.Error($"ProcessRunner >>> [thread-{threadId}] {e.Data}");
lock (outputLock) {
output.AppendLine(e.Data);
}
};

proc.Start();
if (DebugSwitch) {
proc.BeginOutputReadLine();
}
proc.BeginOutputReadLine();
proc.BeginErrorReadLine();

bool exited;
if (timeoutMs <= 0) {
proc.WaitForExit();
exited = true;
} else {
if (proc.WaitForExit(timeoutMs)) {
return;
}
exited = proc.WaitForExit(timeoutMs);
}

if (!exited) {
logger.Warning($"ProcessRunner >>> [thread-{threadId}] Timeout, killing...");
try {
proc.Kill();
proc.Kill(entireProcessTree: true);
logger.Warning($"ProcessRunner >>> [thread-{threadId}] Killed.");
} catch (Exception e) {
logger.Error(e, $"ProcessRunner >>> [thread-{threadId}] Failed to kill");
}
}

try {
proc.WaitForExit();
} catch { /* process already disposed/exited */ }

stdoutDone.Wait(TimeSpan.FromSeconds(5));
stderrDone.Wait(TimeSpan.FromSeconds(5));

lock (outputLock) {
if (!exited) {
output.AppendLine("Killed due to timeout.");
} else {
output.Append("Exit code ").Append(proc.ExitCode);
}
return output.ToString();
}
}
}
}
Expand Down
1 change: 1 addition & 0 deletions OpenUtau/Strings/Strings.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ Do you want to continue by splitting at the nearest position after current playh
<system:String x:Key="errors.install.cpp">Try installing the latest Visual C++ Redistributable. https://learn.microsoft.com/en-US/cpp/windows/latest-supported-vc-redist?view=msvc-170</system:String>
<system:String x:Key="errors.lyrics.regex">Character not allowed in regular expression</system:String>
<system:String x:Key="errors.lyrics.regexpreview">- regular expression error -</system:String>
<system:String x:Key="errors.resampler.failed.message">Resampler failed to create output file(s). Resampler errors like this are often caused by oto.ini configuration issues. Consider generating a singer error report to check for such issues.</system:String>

<system:String x:Key="exesetup.installing">Installing "{0}"...</system:String>
<system:String x:Key="exesetup.linux">To use exe resamplers or wavtools on Linux:
Expand Down
1 change: 1 addition & 0 deletions OpenUtau/Strings/Strings.de-DE.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@
<!--<system:String x:Key="errors.install.cpp">Try installing the latest Visual C++ Redistributable. https://learn.microsoft.com/en-US/cpp/windows/latest-supported-vc-redist?view=msvc-170</system:String>-->
<!--<system:String x:Key="errors.lyrics.regex">Character not allowed in regular expression</system:String>-->
<!--<system:String x:Key="errors.lyrics.regexpreview">- regular expression error -</system:String>-->
<system:String x:Key="errors.resampler.failed.message">Der Resampler konnte keine Ausgabedatei(en) erzeugen. Resampler-Fehler wie dieser werden oft von oto.ini-Konfigurationsfehlern ausgelöst. Generieren Sie einen Sänger-Fehlerbericht, um derartige Fehler zu finden.</system:String>

<!--<system:String x:Key="exesetup.installing">Installing "{0}"...</system:String>-->
<!--<system:String x:Key="exesetup.linux">To use exe resamplers or wavtools on Linux:
Expand Down