From af280d7b27c338c3be7c64b69bf36e8ceed636cb Mon Sep 17 00:00:00 2001 From: ChiKyun Kim Date: Wed, 10 Dec 2025 13:36:35 +0900 Subject: [PATCH] =?UTF-8?q?=EC=98=A4=EB=94=94=EC=98=A4=EC=9E=AC=EC=83=9D?= =?UTF-8?q?=ED=95=A8=EC=88=98=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cs_HMI/SubProject/CommUtil | 2 +- Cs_HMI/SubProject/EnigProtocol | 2 +- .../SuperTonic/.vscode/settings.json | 3 + Cs_HMI/SubProject/SuperTonic/ExampleONNX.cs | 29 +++++++-- Cs_HMI/SubProject/SuperTonic/Helper.cs | 63 +++++++++++++++++++ .../SuperTonic/Supertonic.Netfx48.csproj | 36 +++++------ Cs_HMI/SubProject/SuperTonic/packages.config | 1 + 7 files changed, 112 insertions(+), 24 deletions(-) create mode 100644 Cs_HMI/SubProject/SuperTonic/.vscode/settings.json diff --git a/Cs_HMI/SubProject/CommUtil b/Cs_HMI/SubProject/CommUtil index ed05439..632b087 160000 --- a/Cs_HMI/SubProject/CommUtil +++ b/Cs_HMI/SubProject/CommUtil @@ -1 +1 @@ -Subproject commit ed05439991fdddba2d7123b7a89a89245bcd044c +Subproject commit 632b087c5be6b94ee953a374a25992aa54d56c7c diff --git a/Cs_HMI/SubProject/EnigProtocol b/Cs_HMI/SubProject/EnigProtocol index 4f360f3..8877cb1 160000 --- a/Cs_HMI/SubProject/EnigProtocol +++ b/Cs_HMI/SubProject/EnigProtocol @@ -1 +1 @@ -Subproject commit 4f360f33a7abbd77c517ca2492ccbde53e687099 +Subproject commit 8877cb1a9dbf97228ebb3fd57ca0004fef77fe24 diff --git a/Cs_HMI/SubProject/SuperTonic/.vscode/settings.json b/Cs_HMI/SubProject/SuperTonic/.vscode/settings.json new file mode 100644 index 0000000..013007b --- /dev/null +++ b/Cs_HMI/SubProject/SuperTonic/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "dotnet.preferCSharpExtension": true +} \ No newline at end of file diff --git a/Cs_HMI/SubProject/SuperTonic/ExampleONNX.cs b/Cs_HMI/SubProject/SuperTonic/ExampleONNX.cs index 234a51d..57ef927 100644 --- a/Cs_HMI/SubProject/SuperTonic/ExampleONNX.cs +++ b/Cs_HMI/SubProject/SuperTonic/ExampleONNX.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Threading.Tasks; namespace Supertonic { @@ -11,13 +12,14 @@ namespace Supertonic { public bool UseGpu { get; set; } = false; public string OnnxDir { get; set; } = "assets/onnx"; + public string BaseDir { get; set; } = ""; public int TotalStep { get; set; } = 5; public float Speed { get; set; } = 1.05f; public int NTest { get; set; } = 4; - public List VoiceStyle { get; set; } = new List { "assets/voice_styles/M1.json" }; + public List VoiceStyle { get; set; } = new List { "assets/voice_styles/M2.json" }; public List Text { get; set; } = new List { - "This morning, I took a walk in the park, and the sound of the birds and the breeze was so pleasant that I stopped for a long time just to listen." + "hello , 안녕하세요" }; public string SaveDir { get; set; } = "results"; public bool Batch { get; set; } = false; @@ -58,13 +60,16 @@ namespace Supertonic case "--save-dir" when i + 1 < args.Length: result.SaveDir = args[++i]; break; + case "--base-dir" when i + 1 < args.Length: + result.BaseDir = args[++i]; + break; } } return result; } - static void Main(string[] args) + static async Task Main(string[] args) { Console.WriteLine("=== TTS Inference with ONNX Runtime (C#) ===\n"); @@ -86,10 +91,15 @@ namespace Supertonic int bsz = voiceStylePaths.Count; // --- 2. Load Text to Speech --- // - var textToSpeech = Helper.LoadTextToSpeech(parsedArgs.OnnxDir, parsedArgs.UseGpu); + var onnxdir = System.IO.Path.Combine(parsedArgs.BaseDir, parsedArgs.OnnxDir); + var textToSpeech = Helper.LoadTextToSpeech(onnxdir, parsedArgs.UseGpu); Console.WriteLine(); // --- 3. Load Voice Style --- // + for(int i = 0; i < voiceStylePaths.Count;i++) + { + voiceStylePaths[i] = Path.Combine(parsedArgs.BaseDir, voiceStylePaths[i]); + } var style = Helper.LoadVoiceStyle(voiceStylePaths, verbose: true); // --- 4. Synthesize speech --- // @@ -114,6 +124,8 @@ namespace Supertonic Directory.CreateDirectory(saveDir); } + var playbackTasks = new List(); + for (int b = 0; b < bsz; b++) { string fname = $"{Helper.SanitizeFilename(textList[b], 20)}_{n + 1}.wav"; @@ -125,7 +137,16 @@ namespace Supertonic string outputPath = Path.Combine(saveDir, fname); Helper.WriteWavFile(outputPath, wavOut, textToSpeech.SampleRate); Console.WriteLine($"Saved: {outputPath}"); + + // 비동기로 오디오 재생 (파일 저장과 동시에) + Console.WriteLine($"Playing audio [{b + 1}/{bsz}]..."); + var playTask = Helper.PlayAudioAsync(wavOut, textToSpeech.SampleRate); + playbackTasks.Add(playTask); } + + // 모든 재생이 완료될 때까지 대기 + await Task.WhenAll(playbackTasks); + Console.WriteLine("Playback completed."); } Console.WriteLine("\n=== Synthesis completed successfully! ==="); diff --git a/Cs_HMI/SubProject/SuperTonic/Helper.cs b/Cs_HMI/SubProject/SuperTonic/Helper.cs index cd4ccff..784bf63 100644 --- a/Cs_HMI/SubProject/SuperTonic/Helper.cs +++ b/Cs_HMI/SubProject/SuperTonic/Helper.cs @@ -5,6 +5,8 @@ using System.Linq; using System.Text; using System.Text.Json; using System.Text.RegularExpressions; +using System.Threading.Tasks; +using System.Media; using Microsoft.ML.OnnxRuntime; using Microsoft.ML.OnnxRuntime.Tensors; @@ -877,5 +879,66 @@ namespace Supertonic return chunks; } + + // ============================================================================ + // Audio Playback + // ============================================================================ + + /// + /// 오디오를 스피커로 비동기 재생합니다. + /// + /// float 배열 형태의 오디오 데이터 (-1.0 ~ 1.0) + /// 샘플레이트 (예: 16000, 22050, 44100) + public static async Task PlayAudioAsync(float[] audioData, int sampleRate) + { + await Task.Run(() => + { + try + { + // 임시 WAV 파일 생성 + string tempWavFile = Path.Combine(Path.GetTempPath(), $"temp_audio_{Guid.NewGuid()}.wav"); + WriteWavFile(tempWavFile, audioData, sampleRate); + + // SoundPlayer로 재생 + using (var player = new SoundPlayer(tempWavFile)) + { + player.PlaySync(); // 재생이 끝날 때까지 대기 + } + + // 임시 파일 삭제 + try + { + File.Delete(tempWavFile); + } + catch { /* 임시 파일 삭제 실패 무시 */ } + } + catch (Exception ex) + { + Console.WriteLine($"[Audio Playback Error] {ex.Message}"); + } + }); + } + + /// + /// 오디오 파일을 스피커로 비동기 재생합니다. + /// + /// WAV 파일 경로 + public static async Task PlayWavFileAsync(string wavFilePath) + { + await Task.Run(() => + { + try + { + using (var player = new SoundPlayer(wavFilePath)) + { + player.PlaySync(); // 재생이 끝날 때까지 대기 + } + } + catch (Exception ex) + { + Console.WriteLine($"[WAV Playback Error] {ex.Message}"); + } + }); + } } } diff --git a/Cs_HMI/SubProject/SuperTonic/Supertonic.Netfx48.csproj b/Cs_HMI/SubProject/SuperTonic/Supertonic.Netfx48.csproj index ec63d6d..bf5677b 100644 --- a/Cs_HMI/SubProject/SuperTonic/Supertonic.Netfx48.csproj +++ b/Cs_HMI/SubProject/SuperTonic/Supertonic.Netfx48.csproj @@ -1,6 +1,6 @@  - + Debug @@ -62,37 +62,37 @@ - ..\csharp\packages\Microsoft.Bcl.AsyncInterfaces.10.0.1\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll + .\packages\Microsoft.Bcl.AsyncInterfaces.10.0.1\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll - ..\csharp\packages\Microsoft.ML.OnnxRuntime.Managed.1.23.2\lib\netstandard2.0\Microsoft.ML.OnnxRuntime.dll + .\packages\Microsoft.ML.OnnxRuntime.Managed.1.23.2\lib\netstandard2.0\Microsoft.ML.OnnxRuntime.dll - ..\csharp\packages\System.Buffers.4.6.1\lib\net462\System.Buffers.dll + .\packages\System.Buffers.4.6.1\lib\net462\System.Buffers.dll - ..\csharp\packages\System.IO.Pipelines.10.0.1\lib\net462\System.IO.Pipelines.dll + .\packages\System.IO.Pipelines.10.0.1\lib\net462\System.IO.Pipelines.dll - ..\csharp\packages\System.Memory.4.6.3\lib\net462\System.Memory.dll + .\packages\System.Memory.4.6.3\lib\net462\System.Memory.dll - ..\csharp\packages\System.Numerics.Vectors.4.6.1\lib\net462\System.Numerics.Vectors.dll + .\packages\System.Numerics.Vectors.4.6.1\lib\net462\System.Numerics.Vectors.dll - ..\csharp\packages\System.Runtime.CompilerServices.Unsafe.6.1.2\lib\net462\System.Runtime.CompilerServices.Unsafe.dll + .\packages\System.Runtime.CompilerServices.Unsafe.6.1.2\lib\net462\System.Runtime.CompilerServices.Unsafe.dll - ..\csharp\packages\System.Text.Encodings.Web.10.0.1\lib\net462\System.Text.Encodings.Web.dll + .\packages\System.Text.Encodings.Web.10.0.1\lib\net462\System.Text.Encodings.Web.dll - ..\csharp\packages\System.Text.Json.10.0.1\lib\net462\System.Text.Json.dll + .\packages\System.Text.Json.10.0.1\lib\net462\System.Text.Json.dll - ..\csharp\packages\System.Threading.Tasks.Extensions.4.6.3\lib\net462\System.Threading.Tasks.Extensions.dll + .\packages\System.Threading.Tasks.Extensions.4.6.3\lib\net462\System.Threading.Tasks.Extensions.dll @@ -111,16 +111,16 @@ - + 이 프로젝트는 이 컴퓨터에 없는 NuGet 패키지를 참조합니다. 해당 패키지를 다운로드하려면 NuGet 패키지 복원을 사용하십시오. 자세한 내용은 http://go.microsoft.com/fwlink/?LinkID=322105를 참조하십시오. 누락된 파일은 {0}입니다. - - - - + + + + - - + + \ No newline at end of file diff --git a/Cs_HMI/SubProject/SuperTonic/packages.config b/Cs_HMI/SubProject/SuperTonic/packages.config index 07942d4..f937885 100644 --- a/Cs_HMI/SubProject/SuperTonic/packages.config +++ b/Cs_HMI/SubProject/SuperTonic/packages.config @@ -3,6 +3,7 @@ +