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 ...
随机推荐
- 树莓派4B 关闭休眠,关闭屏保
1.安装 sudo apt install xscreensaver 2.打开xscreensaver sudo xscreensaver-demo 3.设置 参考:https://zhuanlan. ...
- Dapr-3: 从 20000 英尺之上俯瞰 Dapr
第 3 章 从 20000 英尺之上俯瞰 Dapr Dapr at 20,000 feet | Microsoft Docs 在第 1 章中,我们讨论了分布式微服务应用的吸引力.但是,我们也指出了它会 ...
- Linux新用户登录时出现“-bash-4.2$”的解决办法
Linux服务器新建的用户在登录时显示"-bash-4.2$",而不是"user@hostname"的显示方式,出现此问题的原因是在添加普通用户时,用户家目录下 ...
- Debian 11 (bullseye) 国内软件源
本文整理了Debian 11在国内的几个软件源. 1.使用说明 一般情况下,将/etc/apt/sources.list文件中Debian默认的软件仓库地址和安全更新仓库地址修改为国内的镜像地址即 ...
- 浅谈LINUX中/DEV/VDA1文件满了解决方法
1. 先查看内存使用情况 df -h 1 2. 进入/dev/vdal的磁盘挂载的目录 /,查看各个文件占用大小 cd / du -sh * 1 2 注意:进入那个比较大的文件,我这里发现var这个文 ...
- IPV6禁用导致 RabbitMQ 无法启动的问题
问题现象 在开发的过程中遇到了 RabbitMQ 怎么也启动不起来的现象.查看 RabbitMQ 自身的启动日志,并没有发现有什么有用的报错信息,只是从某天开始就一直在打印重启的日志,尝试多次重启也不 ...
- error C1083: 无法打开包括文件:“iostream.h”: No such file or directory
用VS2010打开VC++6程序,按下F5键会发现有错误提示:error C1083: 无法打开包括文件:"iostream.h": No such file or directo ...
- 基于开源IM即时通讯框架MobileIMSDK:RainbowChat v11.6版已发布
关于RainbowChat RainbowChat是一套基于开源IM聊天框架 MobileIMSDK 的产品级移动端IM系统.RainbowChat源于真实运营的产品,解决了大量的屏幕适配.细节优化. ...
- 到底什么是Java AIO?为什么Netty会移除AOI?一文搞懂AIO的本质!
本文由得物技术团队Uni分享,本文有内容修订和大量排版优化. 1.引言 关于Java网络编程中的同步IO和异步IO的区别及原理的文章非常的多,具体来说主要还是在讨论Java BIO和Java NIO这 ...
- 不为人知的网络编程(十一):从底层入手,深度分析TCP连接耗时的秘密
本文作者张彦飞,原题"聊聊TCP连接耗时的那些事儿",有少许改动. 1.引言 对于基于互联网的通信应用(比如IM聊天.推送系统),数据传递时使用TCP协议相对较多.这是因为在TCP ...