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应用
WPF调用FishSpeech的Demo的更多相关文章
- WPF调用Matlab函数方法
有的时候用C#写图像处理方法,比较费事,不如Matlab简单,但是Matlab又做不出WPF那样的好看界面,怎么办呢. 今天正好我要实现这个功能,就顺便写个小例子,给需要的人做个借鉴. 想要用WPF调 ...
- WPF [调用线程无法访问此对象,因为另一个线程拥有该对象。] 解决方案以及如何实现字体颜色的渐变
本文说明WPF [调用线程无法访问此对象,因为另一个线程拥有该对象.] 解决方案以及如何实现字体颜色的渐变 先来看看C#中Timer的简单说明,你想必猜到实现需要用到Timer的相关知识了吧. C# ...
- WPF调用图片路径,或资源图片
一.加载本项目的图片WPF引入了统一资源标识Uri(Unified Resource Identifier)来标识和访问资源.其中较为常见的情况是用Uri加载图像.Uri表达式的一般形式为:协议+授权 ...
- 使用Prism提供的类实现WPF MVVM点餐Demo
使用Prism提供的类实现WPF MVVM点餐Demo 由于公司开发的技术需求,近期在学习MVVM模式开发WPF应用程序.进过一段时间的学习,感受到:学习MVVM模式,最好的方法就是用MVVM做几个D ...
- C# WPF 调用FFMPEG实现“SORRY 为所欲为/王境泽”表情包GIF生成软件
C# WPF 调用FFMPEG实现“SORRY 为所欲为/王境泽”表情包GIF生成 1,调用ffmpeg将外挂字幕“嵌入”视频中,保存副本: 2,调用ffmpeg将副本视频导出为gif图片. 参考资料 ...
- WPF 调用资源图片
原文:WPF 调用资源图片 最近做的wpf项目中,在开发的时候,把图片放到了bin下面,采用了imagePath =System.IO.Directory.GetCurrentDirectory()+ ...
- WPF 调用API修改窗体风格实现真正的无边框窗体
原文:WPF 调用API修改窗体风格实现真正的无边框窗体 WPF中设置无边框窗体似乎是要将WindowStyle设置为None,AllowTransparency=true,这样才能达到WinForm ...
- WPF调用C++生成的dll文件(示例)
注:笔者使用的VS版本为2019.1.打开VS2019,选择文件 -> 新建 -> 项目 2.选择项目 新建项目时选择C++“控制台应用”语言:C++平台:Windows项目类型:空项目 ...
- WPF调用office2010的ppt出错
各位热爱WPF编程小伙伴不可避免的会遇到将ppt嵌入到自己编写的软件,可是有时候会遇到错误,此错误值出现在卸载office2013并安装其他版本office时候会出现.这是由于某些机器上offic ...
- WPF调用Win Form
WPF是win form的下一代版本,现在越来越多的公司使用WPF.如何兼容已有的使用win form开发的应用程序呢?下面有三种方式来在WPF中调用win form. 使用WPF中的WindowsF ...
随机推荐
- 记一次cenos7安装nginx
安装依赖 yum -y install gcc gcc-c++ make libtool zlib zlib-devel openssl openssl-devel pcre pcre-devel 下 ...
- 人工智能大语言模型起源篇,低秩微调(LoRA)
上一篇: <规模法则(Scaling Law)与参数效率的提高> 序言:您在找工作时会不会经常听到LoRA微调,这项技术的来源就是这里了. (12)Hu.Shen.Wallis.Allen ...
- Qt编写物联网管理平台33-设备面板
一.前言 设备面板展示数据,相对于表格展示,可能在一个页面中能够展示的设备数据量少一些,但是有些用户和场景,又需要这种面板的形式,可能更生动形象一些.尤其是经过这么些年的社会的毒打,我的原则是:用户是 ...
- vue3项目中报错:Unexpected mutation of "xxx" prop
vue3 中element 弹窗绑定需要通过v-model,这个时候父级会传个dialogVisible(boolean值)过来,结果会报eslint的错. Unexpected mutation o ...
- IM开发快速入门(二):什么是IM系统的实时性?
本文在编写时参考了博客作者"鹿呦呦"和在线课程"即时消息技术剖析与实战"的相关资料,一并表示感谢. 1.引言 随着移动互联网络的发展,IM技术的应用已经不仅限于 ...
- IM消息ID技术专题(七):网易严选分布式ID的技术选型、优化、落地实践
1.引言 在<IM消息ID技术专题>系列文章的前几篇中,我们已经深切体会到消息ID在分布式IM聊天系统中的重要性以及技术实现难度,各种消息ID生成算法及实现虽然各有优势,但受制于具体的应用 ...
- [密码管理/信息安全] KeePass Java 客户端 : KeePassJava2
序:续<KeePass:密码管理工具> [密码管理/信息安全] 密码管理工具:KeePass vs LastPass vs 1Password - 博客园/千千寰宇 [推荐] 概述 Kee ...
- CF1763C Another Array Problem
人类智慧题.harmis_yz 不会. 题意 \(\tt{Link}\) 给定一个序列 \(\{a_n\}\),可以进行若干次操作,每次可以选择 \(i,j(1 \le i < j \le n) ...
- Linux防火墙端口设置策略
# 当我们在服务器上部署好我们的环境后,一定要检查一下防火墙的端口策略:否则客户端无法连接.# 查看防火墙状态 systemctl status firewalld # 查看防火墙设已开放的端口 # ...
- Spring IOC实现原理,源码深度剖析!
Spring容器高层视图 Spring 启动时读取应用程序提供的Bean配置信息,并在Spring容器中生成一份相应的Bean配置注册表,然后根据这张注册表实例化Bean,装配好Bean之间的依赖关系 ...