WPF調用FishSpeech的Demo
寫了一個FishSpeech的教程:使用FishSpeech進行語音合成推理 - 天命小豬 - 博客園
研究了一下如何調用服務器API,朗讀文本。
經過調研,決定使用NAudio庫播放音頻。遇到了一些問題,如流媒體如何播放。
流媒體請求時需要設定請求方式,否則需要等到流全部加載完成才能繼續。不能用 response = await client.PostAsync(url, content); 而是改用 response = await client.SendAsync(postRequest, HttpCompletionOption.ResponseHeadersRead);
var postRequest = new HttpRequestMessage(HttpMethod.Post, url); postRequest.Content = content; //流媒體請求頭 response = await client.SendAsync(postRequest, HttpCompletionOption.ResponseHeadersRead);
wav流媒體需要用bufferedWaveProvider緩存字節流,并判斷緩沖是否快溢出。
private BufferedWaveProvider bufferedWaveProvider; private bool IsBufferNearlyFull { get { return bufferedWaveProvider != null && bufferedWaveProvider.BufferLength - bufferedWaveProvider.BufferedBytes < bufferedWaveProvider.WaveFormat.AverageBytesPerSecond / 4; } }
播放流媒體需要等待播放完成再結束,否則會提前釋放對象導致播放不完整。
// 等待播放完成 while (bufferedWaveProvider.BufferedBytes != 0) { Debug.WriteLine("等待播放完成"); await Task.Delay(500); }
完整參考:
using NAudio.Wave; using Newtonsoft.Json; using System.Diagnostics; using System.Net.Http; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using System.Threading; namespace WpfApp1 { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private BufferedWaveProvider bufferedWaveProvider; private bool IsBufferNearlyFull { get { return bufferedWaveProvider != null && bufferedWaveProvider.BufferLength - bufferedWaveProvider.BufferedBytes < bufferedWaveProvider.WaveFormat.AverageBytesPerSecond / 4; } } private async void Button_Click(object sender, RoutedEventArgs e) { var url = $"{TextApiServer.Text.Trim()}"; var payload = new { text = $"{TextSource.Text.Trim()}", chunk_length = 200, format = "wav", references = new object[] { }, reference_id = "畢業女", use_memory_cache = "on", normalize = true, streaming = true as bool?, max_new_tokens = 1024, top_p = 0.7, repetition_penalty = 1.2, temperature = 0.7 }; var json = JsonConvert.SerializeObject(payload); var content = new StringContent(json, Encoding.UTF8, "application/json"); try { using (var client = new HttpClient()) { HttpResponseMessage response = null; if (payload.streaming == true) { var postRequest = new HttpRequestMessage(HttpMethod.Post, url); postRequest.Content = content; //流媒體請求頭 response = await client.SendAsync(postRequest, HttpCompletionOption.ResponseHeadersRead); } else { response = await client.PostAsync(url, content); } if (response.IsSuccessStatusCode) { Debug.WriteLine("請求成功"); using (var stream = await response.Content.ReadAsStreamAsync()) { if (payload.format.ToString() == "mp3") { using (var reader = new Mp3FileReader(stream)) using (var waveOut = new WaveOutEvent()) { waveOut.Init(reader); waveOut.Play(); // 等待播放完成 while (waveOut.PlaybackState == PlaybackState.Playing) { await Task.Delay(500); //Thread.Sleep(100); } } Debug.WriteLine("End"); } else if (payload.format.ToString() == "wav") { #region WAV //// 假設音頻格式為 16bit 16kHz 單聲道 var waveFormat = new WaveFormat(44100, 16, 1); bufferedWaveProvider = new BufferedWaveProvider(waveFormat) { BufferDuration = TimeSpan.FromSeconds(20) // 設置緩沖區大小 }; using (var waveOut = new WaveOutEvent()) { waveOut.Init(bufferedWaveProvider); waveOut.Play(); // 5. 持續讀取流數據 byte[] buffer = new byte[4096]; int bytesRead; while ((bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length)) > 0) { if (IsBufferNearlyFull) { Debug.WriteLine("Buffer getting full, taking a break"); //await Task.Delay(500); Thread.Sleep(500); } Debug.WriteLine($"Add bytes,length:{bytesRead}"); bufferedWaveProvider.AddSamples(buffer, 0, bytesRead); } // 等待播放完成 while (bufferedWaveProvider.BufferedBytes != 0) { Debug.WriteLine("等待播放完成"); await Task.Delay(500); } Debug.WriteLine("End"); } #endregion } } } else { Debug.WriteLine($"Error: {response.StatusCode}"); throw new Exception(response.Content.ToString()); } } } catch (Exception ex) { throw ex; } } } }
Git地址:6112562a/WpfAppDemo: WPF demo應用

浙公網安備 33010602011771號