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应用

 

posted @ 2025-02-24 18:01  天命小猪  阅读(101)  评论(0)    收藏  举报