如何在 MediaPlayer 中播放来自 SpeechSynthesizer 的 wav 文件
how to play a wav file from SpeechSynthesizer in MediaPlayer
我有一些代码(在 WPF 应用程序中),当一些文本被复制到剪贴板时,它会使用 SpeechSynthesizer 读出文本(我所有的代码都在这个 post 的底部) .
但是以这种方式播放音频不允许我暂停、倒回或播放等
所以我想我会使用 SpeechSynthesizer 来保存一个 wav 文件。然后使用 MediaPlayer class 因为它很容易暂停、播放等
但是,保存文件后,该文件无法在我的媒体播放器中播放。当我手动 运行 时,该文件很好并且可以完美运行。我想使用 MediaPlayer,因为我已经为它编写了一些代码。
更新
使用示例 on this page 我可以播放我的 wav 文件。我不知道为什么文件在我的代码中没有 运行?在上面的示例中,我知道他们正在使用媒体元素,并且在我的代码中尝试过它没有任何区别。我不播放视频,只播放音频,因此我使用 MediaPlayer。
这是我当前的全部代码。正在保存文件,但据我所知,媒体播放器没有播放任何内容,我的电脑音量开得很高。
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Interop;
using System.IO;
using System.Speech.Synthesis;
using System.Windows.Controls.Primitives;
using System.Windows.Threading;
namespace CSWPFClipboardViewer
{
/// <summary>
/// Main window of the application, also will be used to get clipboard messages.
/// </summary>
public partial class MainWindow : Window
{
#region Private fields
/// <summary>
/// Next clipboard viewer window
/// </summary>
private IntPtr hWndNextViewer;
/// <summary>
/// The <see cref="HwndSource"/> for this window.
/// </summary>
private HwndSource hWndSource;
private bool isViewing;
private MediaPlayer mePlayer = new MediaPlayer();
#endregion
public MainWindow()
{
InitializeComponent();
}
#region Clipboard viewer related methods
private void InitCBViewer()
{
WindowInteropHelper wih = new WindowInteropHelper(this);
hWndSource = HwndSource.FromHwnd(wih.Handle);
hWndSource.AddHook(this.WinProc); // start processing window messages
hWndNextViewer = Win32.SetClipboardViewer(hWndSource.Handle); // set this window as a viewer
isViewing = true;
}
private void CloseCBViewer()
{
// remove this window from the clipboard viewer chain
Win32.ChangeClipboardChain(hWndSource.Handle, hWndNextViewer);
hWndNextViewer = IntPtr.Zero;
hWndSource.RemoveHook(this.WinProc);
pnlContent.Children.Clear();
isViewing = false;
}
private void DrawContent()
{
pnlContent.Children.Clear();
if (Clipboard.ContainsText())
{
string path = @"C:\Users\MyPath\";
string fileName = "MyFile.wav";
// delete previous file if it exists
if (File.Exists(path + fileName))
File.Delete(path + fileName);
// we have some text in the clipboard.
TextBox tb = new TextBox();
tb.VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
tb.FontSize = 24;
tb.Text = Clipboard.GetText();
tb.IsReadOnly = true;
tb.TextWrapping = TextWrapping.Wrap;
pnlContent.Children.Add(tb);
SpeechSynthesizer synthesizer = new SpeechSynthesizer();
synthesizer.Volume = 100; // 0...100
synthesizer.Rate = 3; // -10...10
//Asynchronous
synthesizer.SetOutputToWaveFile(path + fileName);
synthesizer.SpeakCompleted += new EventHandler<SpeakCompletedEventArgs>(synth_SpeakCompleted);
synthesizer.SpeakAsync(Clipboard.GetText());
}
else
{
Label lb = new Label();
lb.Content = "The type of the data in the clipboard is not supported by this sample.";
pnlContent.Children.Add(lb);
}
}
private IntPtr WinProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
switch (msg)
{
case Win32.WM_CHANGECBCHAIN:
if (wParam == hWndNextViewer)
{
// clipboard viewer chain changed, need to fix it.
hWndNextViewer = lParam;
}
else if (hWndNextViewer != IntPtr.Zero)
{
// pass the message to the next viewer.
Win32.SendMessage(hWndNextViewer, msg, wParam, lParam);
}
break;
case Win32.WM_DRAWCLIPBOARD:
// clipboard content changed
this.DrawContent();
// pass the message to the next viewer.
Win32.SendMessage(hWndNextViewer, msg, wParam, lParam);
break;
}
return IntPtr.Zero;
}
#endregion
#region Control event handlers
void synth_SpeakCompleted(object sender, SpeakCompletedEventArgs e)
{
string path = @"C:\Users\MyPath\";
string fileName = "MyFile.wav";
mePlayer.Open(new Uri(path + fileName));
mePlayer.Play();
}
private void btnSwitch_Click(object sender, RoutedEventArgs e)
{
// switching between start/stop viewing state
if (!isViewing)
{
this.InitCBViewer();
btnSwitch.Content = "Stop viewer";
}
else
{
this.CloseCBViewer();
btnSwitch.Content = "Start viewer";
}
}
private void btnClose_Click(object sender, RoutedEventArgs e)
{
this.Close();
}
private void Window_Closed(object sender, EventArgs e)
{
this.CloseCBViewer();
}
#endregion
}
}
C# Win32
using System;
using System.Runtime.InteropServices;
namespace CSWPFClipboardViewer
{
/// <summary>
/// This static class holds the Win32 function declarations and constants needed by
/// this sample application.
/// </summary>
internal static class Win32
{
/// <summary>
/// The WM_DRAWCLIPBOARD message notifies a clipboard viewer window that
/// the content of the clipboard has changed.
/// </summary>
internal const int WM_DRAWCLIPBOARD = 0x0308;
/// <summary>
/// A clipboard viewer window receives the WM_CHANGECBCHAIN message when
/// another window is removing itself from the clipboard viewer chain.
/// </summary>
internal const int WM_CHANGECBCHAIN = 0x030D;
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern IntPtr SetClipboardViewer(IntPtr hWndNewViewer);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern bool ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
}
}
XAML
<Window x:Class="CSWPFClipboardViewer.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"
Title="Clipboard Viewer" Height="500" Width="640" Background="Black" Closed="Window_Closed">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Label Grid.Row="0" Foreground="White" Margin="6,0,6,0">Clipboard content:</Label>
<StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Right">
<Button x:Name="btnSwitch" Width="90" Height="25" Content="Start viewer" Padding="3" Margin="6,6,6,6" Click="btnSwitch_Click" />
<Button x:Name="btnClose" Width="90" Height="25" Content="Close" Padding="3" Margin="6,6,6,6" Click="btnClose_Click" />
</StackPanel>
<DockPanel x:Name="pnlContent" Grid.Row="1" Background="White" Margin="6,6,6,6" LastChildFill="True"/>
</Grid>
默认情况下 synthesizer.SpeakAsync
将使用扬声器作为输出。您将输出设置为波形文件。如果您现在调用 synthesizer.SpeakAsync
合成器将 "speak" 到波形文件,在这种情况下意味着写入它。所以 synthesizer.SpeakAsync
将 不会 播放任何声音。
有关更多指导,请参阅示例 here。
一旦创建了 wav 文件,您就可以用媒体播放器打开它。
synthesizer.SpeakAsync("Youre text goes here");
var pathUri = new Uri(path);
player.Open(pathUri.AbsoluteUri);
当我试图复制你的问题时,我发现了一些非常有趣的东西。令人惊讶的是,我遇到了同样的问题。为了调试它,我探索了 MediaPlayer api 并在我的代码中添加了 MediaFailed
事件处理程序。
令我惊讶的是,每次我播放某些内容时,都会调用处理程序并出现以下内部异常:
MILAVERR_INVALIDWMPVERSION (Exception from HRESULT: 0x88980507)
.
更多的谷歌搜索导致 this post 由于少数国家的反竞争政府政策 windows 10 缺少常见的媒体应用程序。
要解决此问题,您可以确保安装了 WMP 10 或更高版本,或者直接使用 SoundPlayer
。
private SoundPlayer player = new SoundPlayer();
player.SoundLocation = System.IO.Path.Combine(path, fileName);
player.Play();
我有一些代码(在 WPF 应用程序中),当一些文本被复制到剪贴板时,它会使用 SpeechSynthesizer 读出文本(我所有的代码都在这个 post 的底部) .
但是以这种方式播放音频不允许我暂停、倒回或播放等
所以我想我会使用 SpeechSynthesizer 来保存一个 wav 文件。然后使用 MediaPlayer class 因为它很容易暂停、播放等
但是,保存文件后,该文件无法在我的媒体播放器中播放。当我手动 运行 时,该文件很好并且可以完美运行。我想使用 MediaPlayer,因为我已经为它编写了一些代码。
更新
使用示例 on this page 我可以播放我的 wav 文件。我不知道为什么文件在我的代码中没有 运行?在上面的示例中,我知道他们正在使用媒体元素,并且在我的代码中尝试过它没有任何区别。我不播放视频,只播放音频,因此我使用 MediaPlayer。
这是我当前的全部代码。正在保存文件,但据我所知,媒体播放器没有播放任何内容,我的电脑音量开得很高。
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Interop;
using System.IO;
using System.Speech.Synthesis;
using System.Windows.Controls.Primitives;
using System.Windows.Threading;
namespace CSWPFClipboardViewer
{
/// <summary>
/// Main window of the application, also will be used to get clipboard messages.
/// </summary>
public partial class MainWindow : Window
{
#region Private fields
/// <summary>
/// Next clipboard viewer window
/// </summary>
private IntPtr hWndNextViewer;
/// <summary>
/// The <see cref="HwndSource"/> for this window.
/// </summary>
private HwndSource hWndSource;
private bool isViewing;
private MediaPlayer mePlayer = new MediaPlayer();
#endregion
public MainWindow()
{
InitializeComponent();
}
#region Clipboard viewer related methods
private void InitCBViewer()
{
WindowInteropHelper wih = new WindowInteropHelper(this);
hWndSource = HwndSource.FromHwnd(wih.Handle);
hWndSource.AddHook(this.WinProc); // start processing window messages
hWndNextViewer = Win32.SetClipboardViewer(hWndSource.Handle); // set this window as a viewer
isViewing = true;
}
private void CloseCBViewer()
{
// remove this window from the clipboard viewer chain
Win32.ChangeClipboardChain(hWndSource.Handle, hWndNextViewer);
hWndNextViewer = IntPtr.Zero;
hWndSource.RemoveHook(this.WinProc);
pnlContent.Children.Clear();
isViewing = false;
}
private void DrawContent()
{
pnlContent.Children.Clear();
if (Clipboard.ContainsText())
{
string path = @"C:\Users\MyPath\";
string fileName = "MyFile.wav";
// delete previous file if it exists
if (File.Exists(path + fileName))
File.Delete(path + fileName);
// we have some text in the clipboard.
TextBox tb = new TextBox();
tb.VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
tb.FontSize = 24;
tb.Text = Clipboard.GetText();
tb.IsReadOnly = true;
tb.TextWrapping = TextWrapping.Wrap;
pnlContent.Children.Add(tb);
SpeechSynthesizer synthesizer = new SpeechSynthesizer();
synthesizer.Volume = 100; // 0...100
synthesizer.Rate = 3; // -10...10
//Asynchronous
synthesizer.SetOutputToWaveFile(path + fileName);
synthesizer.SpeakCompleted += new EventHandler<SpeakCompletedEventArgs>(synth_SpeakCompleted);
synthesizer.SpeakAsync(Clipboard.GetText());
}
else
{
Label lb = new Label();
lb.Content = "The type of the data in the clipboard is not supported by this sample.";
pnlContent.Children.Add(lb);
}
}
private IntPtr WinProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
switch (msg)
{
case Win32.WM_CHANGECBCHAIN:
if (wParam == hWndNextViewer)
{
// clipboard viewer chain changed, need to fix it.
hWndNextViewer = lParam;
}
else if (hWndNextViewer != IntPtr.Zero)
{
// pass the message to the next viewer.
Win32.SendMessage(hWndNextViewer, msg, wParam, lParam);
}
break;
case Win32.WM_DRAWCLIPBOARD:
// clipboard content changed
this.DrawContent();
// pass the message to the next viewer.
Win32.SendMessage(hWndNextViewer, msg, wParam, lParam);
break;
}
return IntPtr.Zero;
}
#endregion
#region Control event handlers
void synth_SpeakCompleted(object sender, SpeakCompletedEventArgs e)
{
string path = @"C:\Users\MyPath\";
string fileName = "MyFile.wav";
mePlayer.Open(new Uri(path + fileName));
mePlayer.Play();
}
private void btnSwitch_Click(object sender, RoutedEventArgs e)
{
// switching between start/stop viewing state
if (!isViewing)
{
this.InitCBViewer();
btnSwitch.Content = "Stop viewer";
}
else
{
this.CloseCBViewer();
btnSwitch.Content = "Start viewer";
}
}
private void btnClose_Click(object sender, RoutedEventArgs e)
{
this.Close();
}
private void Window_Closed(object sender, EventArgs e)
{
this.CloseCBViewer();
}
#endregion
}
}
C# Win32
using System;
using System.Runtime.InteropServices;
namespace CSWPFClipboardViewer
{
/// <summary>
/// This static class holds the Win32 function declarations and constants needed by
/// this sample application.
/// </summary>
internal static class Win32
{
/// <summary>
/// The WM_DRAWCLIPBOARD message notifies a clipboard viewer window that
/// the content of the clipboard has changed.
/// </summary>
internal const int WM_DRAWCLIPBOARD = 0x0308;
/// <summary>
/// A clipboard viewer window receives the WM_CHANGECBCHAIN message when
/// another window is removing itself from the clipboard viewer chain.
/// </summary>
internal const int WM_CHANGECBCHAIN = 0x030D;
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern IntPtr SetClipboardViewer(IntPtr hWndNewViewer);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern bool ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
}
}
XAML
<Window x:Class="CSWPFClipboardViewer.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"
Title="Clipboard Viewer" Height="500" Width="640" Background="Black" Closed="Window_Closed">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Label Grid.Row="0" Foreground="White" Margin="6,0,6,0">Clipboard content:</Label>
<StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Right">
<Button x:Name="btnSwitch" Width="90" Height="25" Content="Start viewer" Padding="3" Margin="6,6,6,6" Click="btnSwitch_Click" />
<Button x:Name="btnClose" Width="90" Height="25" Content="Close" Padding="3" Margin="6,6,6,6" Click="btnClose_Click" />
</StackPanel>
<DockPanel x:Name="pnlContent" Grid.Row="1" Background="White" Margin="6,6,6,6" LastChildFill="True"/>
</Grid>
默认情况下 synthesizer.SpeakAsync
将使用扬声器作为输出。您将输出设置为波形文件。如果您现在调用 synthesizer.SpeakAsync
合成器将 "speak" 到波形文件,在这种情况下意味着写入它。所以 synthesizer.SpeakAsync
将 不会 播放任何声音。
有关更多指导,请参阅示例 here。
一旦创建了 wav 文件,您就可以用媒体播放器打开它。
synthesizer.SpeakAsync("Youre text goes here");
var pathUri = new Uri(path);
player.Open(pathUri.AbsoluteUri);
当我试图复制你的问题时,我发现了一些非常有趣的东西。令人惊讶的是,我遇到了同样的问题。为了调试它,我探索了 MediaPlayer api 并在我的代码中添加了 MediaFailed
事件处理程序。
令我惊讶的是,每次我播放某些内容时,都会调用处理程序并出现以下内部异常:
MILAVERR_INVALIDWMPVERSION (Exception from HRESULT: 0x88980507)
.
更多的谷歌搜索导致 this post 由于少数国家的反竞争政府政策 windows 10 缺少常见的媒体应用程序。
要解决此问题,您可以确保安装了 WMP 10 或更高版本,或者直接使用 SoundPlayer
。
private SoundPlayer player = new SoundPlayer();
player.SoundLocation = System.IO.Path.Combine(path, fileName);
player.Play();