基于baiduAI完成的一个语音合成小程序使用的是Wpf做的界面后台C# .Net4.0工具Vsual Studio2017
只是其他功能也可以这样开发不过得先注册一个Baidu账号 在BaiduAI首页点击产品服务找到语音识别点击使用即可注册应用将几个Key值填入程序即可也可以做成从config读取都行 做的有些地方确实有漏洞不过大体功能都实现了 1.开发BaiduAI需要从NuGet中安装baiduai组件顺带安装Newtonsoft.Json.dll组件 2.页面代码
<Window x:Class="语音合成.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:语音合成"
mc:Ignorable="d"
Background="Transparent"
AllowsTransparency="True"
WindowStyle="None"
Title="MainWindow" Height="450" Width="300" MaxHeight="450" MaxWidth="300" MinHeight="450" MinWidth="300"
//MouseLeftButtonDown事件用于移动没有样式之后的windows窗体
MouseLeftButtonDown="Window_MouseLeftButtonDown" Icon="ico/sound.png">
<Window.Resources>//存放样式
//关闭按钮的样式
<!--Btn_Close_style_Start-->
<Style x:Key="Btn_Close_style" TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Image Name="btncl" Source="ico/close.png" />
<ControlTemplate.Triggers>
//触发器用于改善Button加图后鼠标放上变白的情况
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Source" Value="ico/mclose.png" TargetName="btncl"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!--Btn_Close_style_End-->
//播放按钮的样式
<!--Btn_Play_style_Start-->
<Style x:Key="Btn_Play_style" TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Image Width="45" Name="btncl" Source="ico/play.png"/>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Source" Value="ico/mplay.png" TargetName="btncl"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!--Btn_Play_style_End-->
//播放按钮停止后的样式
<!--Btn_Pause_style_Start-->
<Style x:Key="Btn_Pause_style" TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Image Width="45" Name="btncl" Source="ico/pause.png"/>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Source" Value="ico/mpause.png" TargetName="btncl"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!--Btn_Pause_style_End-->
//上传处理按钮的样式
<!--Btn_Upload_style_Start-->
<Style x:Key="Btn_Upload_style" TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Image Width="45" Name="btncl" Source="ico/upload.png"/>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Source" Value="ico/mupload.png" TargetName="btncl"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!--Btn_Upload_style_End-->
//上传处理按钮的样式将样式反转可以明显看出是否在上传
<!--Btn_Back_Upload_style_Start-->
<Style x:Key="Btn_Back_Upload_style" TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Image Width="45" Name="btncl" Source="ico/mupload.png"/>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Source" Value="ico/upload.png" TargetName="btncl"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!--Btn_Back_Upload_style_End-->
//textBox公共样式文件
<!--Tb_style_Start-->
<Style TargetType="TextBox">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Margin" Value="4,0"/>
</Style>
<!--Tb_style_End-->
//特定的几个Broader美化标签的样式
<!--Br_style_Start-->
<Style x:Key="Br_style" TargetType="Border">
<Setter Property="CornerRadius" Value="5"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="BorderBrush" Value="#FF2E2525"/>
<Setter Property="Margin" Value="5,2"/>
</Style>
<!--Br_style_End-->
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="350"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
//背景美化
<Border BorderThickness="1" BorderBrush="Gray" CornerRadius="10" Grid.ColumnSpan="2" Grid.RowSpan=">
<Border.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF7AB0C9" Offset="0"/>
<GradientStop Color="#FF6767A0" Offset="0.996"/>
<GradientStop Color="#FF828282" Offset="0.51"/>
<GradientStop Color="#FF6BC3AF" Offset="0.151"/>
</LinearGradientBrush>
</Border.Background>
</Border>
//图标
<Image Source="ico/sound.png" Margin="10,0,0,0" VerticalAlignment="Center" HorizontalAlignment="Left"/>
//Title
<Label Content="语音合成" HorizontalAlignment="Center" Margin="4,0,0,0" VerticalContentAlignment="Center" FontSize="16" Grid.Row="0" Grid.Column="0" FontFamily="Tahoma"/>
//Close_Button
<Button Style="{DynamicResource Btn_Close_style}" Name="Btn_Close" Click="Button_Click" Margin="10,5" Width="20" Grid.Column="1" HorizontalAlignment="Right" />
//Title_TextBox
<Border Style="{StaticResource Br_style}" Background="Transparent" Grid.Row="1" Grid.ColumnSpan="2">
<TextBox Name="TB_title" Height="25" FontSize="20"/>
</Border>
//Content_TextBox
<Border Style="{StaticResource Br_style}" Grid.Row="2" Grid.ColumnSpan="2">
<TextBox Name="TB_content" Text="拖入txt文件即可使用" FontSize="16" AllowDrop="True" PreviewDragOver="TB_content_Drop" TextWrapping="Wrap" UndoLimit="96"/>
</Border>
//播放Button并将上面的样式置入
<Button Style="{DynamicResource Btn_Play_style}" Name="Btn_Sound" Grid.Row="3" Margin="5" Click="Btn_Sound_Click" IsEnabled="False"/>
//上传
<Button Style="{DynamicResource Btn_Upload_style}" Name="Btn_Upload" Grid.Row="3" Grid.Column="1" Margin="5" Background="Black" Click="Btn_Upload_Click"/>
//下面两个分别是缓冲圈和提示操作错误用的
<Image Name="Img_Buffer" Source="ico/current.png" Width="24" Height="24" Grid.Row="2" Grid.ColumnSpan="2" VerticalAlignment="Center" HorizontalAlignment="Center" Visibility="Collapsed"/>
<Label Name="Lab_Prompt" Width="140" Height="40" Background="Transparent" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" Content="请拉入txt文件" Visibility="Collapsed" Grid.Row="2" Grid.ColumnSpan="2" FontSize="20" Foreground="#FF9E2626" AllowDrop="True" PreviewDragOver="TB_content_Drop"/>
</Grid>
</Window>
3.后台代码(全部写在了一起)
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
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 Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Baidu.Aip.Speech;
namespace 语音合成
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
//判断是否在播放
public bool IsSound { get; set; } = false;
//判断是否在上传用于控制缓冲圈和控件的开启关闭
public bool IsUpload { get; set; } = false;
//BaiduAI重要的三个属性App_ID,API_Key,SECRET_KEY用于生成token可以通过创建软件获取
public string APP_ID { get; } = "";
public string API_KEY { get; } = "";
public string SECRET_KEY { get; } = "";
//用于播放生成的音频文件
MediaPlayer player = new MediaPlayer();
//用于存放内容
string conetnt;
//存放文件地址
public string Path { get; set; } = "";
public MainWindow()
{
InitializeComponent();
}
//实现拖拽窗口的事件
private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
this.DragMove();
}
//关闭
private void Button_Click(object sender, RoutedEventArgs e)
{
this.Close();
}
//播放
private void Btn_Sound_Click(object sender, RoutedEventArgs e)
{
//判断是否播放了播放就暂停
if (IsSound)
{
if (player.CanPause)
player.Pause();
Btn_Sound.Style = (Style)this.FindResource("Btn_Play_style");
}
else
{
if (Path != "")
{
//添加播放完成事件
player.MediaEnded += Play_stop_Event;
player.Play();
}
Btn_Sound.Style = (Style)this.FindResource("Btn_Pause_style");
}
IsSound = !IsSound;
}
//播放完成后改回样式
private void Play_stop_Event(object sender, EventArgs e)
{
Btn_Sound.Style = (Style)this.FindResource("Btn_Play_style");
IsSound = false;
}
//上传
private void Btn_Upload_Click(object sender, RoutedEventArgs e)
{
//将前端控件样式进行更改体现出正在对文本文件进行处理
Lab_Prompt.Visibility = Visibility.Collapsed;
Btn_Upload.Style = (Style)this.FindResource("Btn_Back_Upload_style");
IsUpload = true;
Btn_Upload.IsEnabled = false;
Img_Buffer.Visibility = Visibility.Visible;
TB_content.IsEnabled = false;
//生成token
var client = new Tts(API_KEY, SECRET_KEY);
//设置多少延时之后未成功算失败
client.Timeout = 60000;
//初始化一个旋转属性并设置旋转中心(这里的缓冲图片设置的是24*24)
RotateTransform rotate = new RotateTransform()
{
CenterX = 12,
CenterY = 12
};
//获取内容
conetnt = TB_content.Text;
//获取长度
int leng = conetnt.Length;
//由于最大上传文件为1024B所以直接以500个字符为分段进行截取防止意外
int cs = leng/ 500;
//用于判断有没有多出的字符
int ys = leng % 500;
//有的话就对循环次数进行+1
cs = ys == 0 ? cs : cs+1;
new Thread(() =>
{
//设置基本返回信息(还有语调等可以设置看需求进行添加调试)
var option = new Dictionary<string, object>()
{
{"spd", 4}, // 语速
{"vol", 9}, // 音量
{"per", 0} // 发音人
};
//判断输入的是文件还是个人输入如果是就在D盘生成
Path = Path == "" ? "D:\\yuyin.mp3" : $"{ Path}.mp3";
//先进行一个连同测试测试与服务器连通是否正常
var result = client.Synthesis(conetnt[0].ToString(), option);
//创建数组存放返回文件
byte[] mic= { };
for (int i = 0; i < cs; i++)
{
//判断连通是否正常
if (result.ErrorCode == 0)
{
//判断字符长度是否小于500小于的话直接发送
if(leng>500)
//将前面的字符分开发送
result = client.Synthesis(conetnt.Substring(i*500,cs-1==i?leng-500:500), option);
else
result = client.Synthesis(conetnt, option);
//用于将返回的Byte[]合并成一个文件
byte[] nCon = new byte[mic.Length+ result.Data.Length];
mic.CopyTo(nCon,0) ;
result.Data.CopyTo(nCon,mic.Length);
mic = nCon;
}
else
{
//如果出错则显示生成错误
this.Dispatcher.Invoke(new Action(() =>
{
Lab_Prompt.Visibility = Visibility.Visible;
Lab_Prompt.Content = "生成错误";
IsUpload = false;
return;
}));
}
}
//将Byte[]保存
File.WriteAllBytes(Path, mic);
//将音频文件加载到MediaPlayer类中用于播放
this.Dispatcher.Invoke(new Action(() =>
{
player.Open(new Uri(Path, UriKind.Absolute));
IsUpload = false;
}));
})
{ IsBackground = true }.Start();
//缓冲圈线程
new Thread(() =>
{
int i = 1;
while (IsUpload)
{
//每十毫秒更新一次ui比较流畅
Thread.Sleep(10);
if (i >= 360)
i = 1;
//每次加5度旋转
i += 5;
this.Dispatcher.Invoke(new Action(() =>
{
//参数附加并实现变化
rotate.Angle = i;
Img_Buffer.RenderTransform = rotate;
}));
}
this.Dispatcher.Invoke(new Action(() =>
{
//缓冲圈结束后将控件解锁和恢复
Img_Buffer.Visibility = Visibility.Collapsed;
Btn_Upload.Style = (Style)this.FindResource("Btn_Upload_style");
Btn_Upload.IsEnabled = true;
TB_content.IsEnabled = true;
Btn_Sound.IsEnabled = true;
}));
})
{ IsBackground = true }.Start();
}
//文件拖入大实现使用的是DropOver事件
private void TB_content_Drop(object sender, DragEventArgs e)
{
Lab_Prompt.Visibility = Visibility.Collapsed;
string msg = "Drop";
if (e.Data.GetDataPresent(DataFormats.FileDrop))
{
msg = ((System.Array)e.Data.GetData(DataFormats.FileDrop)).GetValue(0).ToString();
}
string[] msgs = msg.Split('.');
//截取后缀判断是否符合要求不符合
if (msgs[msgs.Length-1] == "txt")
{
Path = msg;
TB_title.Text = Path;
TB_content.Text =File.ReadAllText(Path,Encoding.Default);
return;
}
Lab_Prompt.Content=“请放入txt文件”;
Lab_Prompt.Visibility = Visibility.Visible;
}
}
}