I have some that code (in a WPF application) that when some text is copied to the clipboard it will then read the text out using SpeechSynthesizer (all my code is at the bottom of this post).
However playing the audio this way doesn't allow me to pause, rewind or play etc.
So I thought I would use the SpeechSynthesizer to save a wav file. Then use the MediaPlayer class as it is quite easy to pause, play etc.
However the file does not play in my media player after saving the file. The file is fine and works perfectly when I run it manually. I want to use the MediaPlayer as I have some code already written for it.
Update
Using the example on this page I can play my wav file. I don't know why the file doesn't run in my code though? In the example above I know they are using a Media Element and have tried that in my code it makes no difference. I am not playing videos only audio hence why I am using the MediaPlayer.
This is all of my current code. The file is being saved but nothing is being played by the media player as far as I can tell, I have the volume up very high on my computer.
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>
By default synthesizer.SpeakAsync
will use the speakers as output. You set the output to a wave file. If you now call synthesizer.SpeakAsync
the synthesizer will "speak" to the wave file, which in this case means writing to it. So synthesizer.SpeakAsync
will not play any audible sound.
See the example here for more guidiance.
As soon as the wav file is created you can open it with the media player.
synthesizer.SpeakAsync("Youre text goes here");
var pathUri = new Uri(path);
player.Open(pathUri.AbsoluteUri);