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 ...
随机推荐
- vmware ESXi快速创建新的虚拟机
准备工作:新虚拟机Win10 安装后,需要windows update,更新补丁到最新,关机.(本文案例win10-Amadeus) 在数据盘新建Win10-Users文件夹(可自定义) 复制win ...
- 迁移现有用户数据到ABP vNext
前言 使用 ABP vNext(下文简称 ABP)时,通常都是从 cli 开始新建模板,从一个空项目开始.对已经存续的项目来说,现有的数据,特别是用户等核心数据需要进行迁移. 老的项目,随着规模越来越 ...
- Linux 管理面板云帮手、APPNODE与宝塔哪个好
阿里云服务器推荐购买99元 由于用作服务器的 Linux 主机通常都没有图形化界面,与日常使用的 Windows .MAC有着很大的差别,一些必备组件的安装或更新就很费时间,后期维护也费神.服务器管理 ...
- Vue.js 监听属性的使用
示例源码: <div id = "computed_props"> 千米 : <input type = "text" v-model = & ...
- Qml 中实现毛玻璃效果
[写在前面] 毛玻璃效果(Acrylic Effect)是一种常见的 UI 设计风格,它通过模糊背景并添加透明度和噪声效果,使界面元素看起来像是半透明的磨砂玻璃. 本文将介绍如何使用 Qml 实现这种 ...
- DVWA靶场Insecure CAPTCHA(不安全验证)漏洞所有级别通关教程及源码审计
Insecure CAPTCHA(不安全验证) Insecure CAPTCHA(不安全验证)漏洞指的是在实现 CAPTCHA(完全自动化公共图灵测试区分计算机和人类)机制时,未能有效保护用户输入的验 ...
- 特殊数据类型的深度分析:JSON、数组和 HSTORE 的实用价值
title: 特殊数据类型的深度分析:JSON.数组和 HSTORE 的实用价值 date: 2025/1/4 updated: 2025/1/4 author: cmdragon excerpt: ...
- Solution Set -「LOCAL」冲刺省选 Round VII
\(\mathscr{Summary}\) 三道结论题,毁灭吧. A 题一开始思路偏了,发现答案最高 bit 能固定之后接下来的结论就顺理成章了. B 题哈哈哈哈又是经典:我结论猜对了,然 ...
- biancheng-MongoDB教程
目录http://c.biancheng.net/mongodb2/ 1NoSQL是什么2MongoDB是什么3Windows安装MongoDB4Linux安装MongoDB5MacOS安装Mongo ...
- linux:搭建 WordPress 个人站点
参考:链接 介绍 WordPress 是一款使用 PHP 语言开发的博客平台,您可使用通过 WordPress 搭建属于个人的博客平台.本文以 CentOS 6.5 操作系统为例,手动搭建 WordP ...