Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve TextToSpeech function by adding a speech rate parameter #24798

Open
wants to merge 2 commits into
base: net9.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/Essentials/samples/Samples/View/TextToSpeechPage.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@
<Label Text="{Binding Pitch}" HorizontalOptions="Center" IsVisible="{Binding AdvancedOptions}"/>
<Slider Value="{Binding Pitch}" Minimum="0.0" Maximum="2.0" IsVisible="{Binding AdvancedOptions}"/>

<Label Text="Rate" HorizontalOptions="Start" IsVisible="{Binding AdvancedOptions}"/>
<Label Text="{Binding Rate}" HorizontalOptions="Center" IsVisible="{Binding AdvancedOptions}"/>
<Slider Value="{Binding Rate}" Minimum="0.1" Maximum="2.0" IsVisible="{Binding AdvancedOptions}"/>

<Button Text="Pick Locale" Command="{Binding PickLocaleCommand}" IsVisible="{Binding AdvancedOptions}"/>
<Label Text="{Binding Locale}" IsVisible="{Binding AdvancedOptions}"/>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public class TextToSpeechViewModel : BaseViewModel
bool advancedOptions;
float volume;
float pitch;
float rate;
string locale = "Default";
Locale selectedLocale;

Expand All @@ -30,6 +31,7 @@ public TextToSpeechViewModel()
AdvancedOptions = false;
Volume = 1.0f;
Pitch = 1.0f;
Rate = 1.0f;
}

public override void OnDisappearing()
Expand All @@ -55,7 +57,8 @@ void OnSpeak(bool multiple)
{
Volume = Volume,
Pitch = Pitch,
Locale = selectedLocale
Locale = selectedLocale,
Rate=Rate
};
}

Expand Down Expand Up @@ -141,6 +144,12 @@ public float Pitch
set => SetProperty(ref pitch, value);
}

public float Rate
{
get => rate;
set => SetProperty(ref rate, value);
}

public string Locale
{
get => locale;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -845,6 +845,8 @@ Microsoft.Maui.Media.SpeechOptions.Locale.get -> Microsoft.Maui.Media.Locale?
Microsoft.Maui.Media.SpeechOptions.Locale.set -> void
Microsoft.Maui.Media.SpeechOptions.Pitch.get -> float?
Microsoft.Maui.Media.SpeechOptions.Pitch.set -> void
Microsoft.Maui.Media.SpeechOptions.Rate.get -> float?
Microsoft.Maui.Media.SpeechOptions.Rate.set -> void
Microsoft.Maui.Media.SpeechOptions.SpeechOptions() -> void
Microsoft.Maui.Media.SpeechOptions.Volume.get -> float?
Microsoft.Maui.Media.SpeechOptions.Volume.set -> void
Expand Down
2 changes: 2 additions & 0 deletions src/Essentials/src/PublicAPI/net-ios/PublicAPI.Shipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -839,6 +839,8 @@ Microsoft.Maui.Media.SpeechOptions.Locale.get -> Microsoft.Maui.Media.Locale?
Microsoft.Maui.Media.SpeechOptions.Locale.set -> void
Microsoft.Maui.Media.SpeechOptions.Pitch.get -> float?
Microsoft.Maui.Media.SpeechOptions.Pitch.set -> void
Microsoft.Maui.Media.SpeechOptions.Rate.get -> float?
Microsoft.Maui.Media.SpeechOptions.Rate.set -> void
Microsoft.Maui.Media.SpeechOptions.SpeechOptions() -> void
Microsoft.Maui.Media.SpeechOptions.Volume.get -> float?
Microsoft.Maui.Media.SpeechOptions.Volume.set -> void
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -839,6 +839,8 @@ Microsoft.Maui.Media.SpeechOptions.Locale.get -> Microsoft.Maui.Media.Locale?
Microsoft.Maui.Media.SpeechOptions.Locale.set -> void
Microsoft.Maui.Media.SpeechOptions.Pitch.get -> float?
Microsoft.Maui.Media.SpeechOptions.Pitch.set -> void
Microsoft.Maui.Media.SpeechOptions.Rate.get -> float?
Microsoft.Maui.Media.SpeechOptions.Rate.set -> void
Microsoft.Maui.Media.SpeechOptions.SpeechOptions() -> void
Microsoft.Maui.Media.SpeechOptions.Volume.get -> float?
Microsoft.Maui.Media.SpeechOptions.Volume.set -> void
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -800,6 +800,8 @@ Microsoft.Maui.Media.SpeechOptions.Locale.get -> Microsoft.Maui.Media.Locale?
Microsoft.Maui.Media.SpeechOptions.Locale.set -> void
Microsoft.Maui.Media.SpeechOptions.Pitch.get -> float?
Microsoft.Maui.Media.SpeechOptions.Pitch.set -> void
Microsoft.Maui.Media.SpeechOptions.Rate.get -> float?
Microsoft.Maui.Media.SpeechOptions.Rate.set -> void
Microsoft.Maui.Media.SpeechOptions.SpeechOptions() -> void
Microsoft.Maui.Media.SpeechOptions.Volume.get -> float?
Microsoft.Maui.Media.SpeechOptions.Volume.set -> void
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -799,6 +799,8 @@ Microsoft.Maui.Media.SpeechOptions.Locale.get -> Microsoft.Maui.Media.Locale?
Microsoft.Maui.Media.SpeechOptions.Locale.set -> void
Microsoft.Maui.Media.SpeechOptions.Pitch.get -> float?
Microsoft.Maui.Media.SpeechOptions.Pitch.set -> void
Microsoft.Maui.Media.SpeechOptions.Rate.get -> float?
Microsoft.Maui.Media.SpeechOptions.Rate.set -> void
Microsoft.Maui.Media.SpeechOptions.SpeechOptions() -> void
Microsoft.Maui.Media.SpeechOptions.Volume.get -> float?
Microsoft.Maui.Media.SpeechOptions.Volume.set -> void
Expand Down
2 changes: 2 additions & 0 deletions src/Essentials/src/PublicAPI/net/PublicAPI.Shipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -781,6 +781,8 @@ Microsoft.Maui.Media.SpeechOptions.Locale.get -> Microsoft.Maui.Media.Locale?
Microsoft.Maui.Media.SpeechOptions.Locale.set -> void
Microsoft.Maui.Media.SpeechOptions.Pitch.get -> float?
Microsoft.Maui.Media.SpeechOptions.Pitch.set -> void
Microsoft.Maui.Media.SpeechOptions.Rate.get -> float?
Microsoft.Maui.Media.SpeechOptions.Rate.set -> void
Microsoft.Maui.Media.SpeechOptions.SpeechOptions() -> void
Microsoft.Maui.Media.SpeechOptions.Volume.get -> float?
Microsoft.Maui.Media.SpeechOptions.Volume.set -> void
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -781,6 +781,8 @@ Microsoft.Maui.Media.SpeechOptions.Locale.get -> Microsoft.Maui.Media.Locale?
Microsoft.Maui.Media.SpeechOptions.Locale.set -> void
Microsoft.Maui.Media.SpeechOptions.Pitch.get -> float?
Microsoft.Maui.Media.SpeechOptions.Pitch.set -> void
Microsoft.Maui.Media.SpeechOptions.Rate.get -> float?
Microsoft.Maui.Media.SpeechOptions.Rate.set -> void
Microsoft.Maui.Media.SpeechOptions.SpeechOptions() -> void
Microsoft.Maui.Media.SpeechOptions.Volume.get -> float?
Microsoft.Maui.Media.SpeechOptions.Volume.set -> void
Expand Down
5 changes: 4 additions & 1 deletion src/Essentials/src/TextToSpeech/TextToSpeech.android.cs
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,10 @@ public async Task SpeakAsync(string text, int max, SpeechOptions options, Cancel
else
tts.SetPitch(TextToSpeechImplementation.PitchDefault);

tts.SetSpeechRate(1.0f);
if (options?.Rate.HasValue ?? false)
tts.SetSpeechRate((float)options.Rate);
else
tts.SetSpeechRate(1.0f);

var parts = TextToSpeech.SplitSpeak(text, max);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ static AVSpeechUtterance GetSpeechUtterance(string text, SpeechOptions options)

if (options.Volume.HasValue)
speechUtterance.Volume = options.Volume.Value;

if (options.Rate.HasValue)
speechUtterance.Rate = options.Rate.Value;
}

return speechUtterance;
Expand Down
3 changes: 3 additions & 0 deletions src/Essentials/src/TextToSpeech/TextToSpeech.macos.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ async Task PlatformSpeakAsync(string text, SpeechOptions options, CancellationTo

if (options.Locale != null)
ss.Voice = options.Locale.Id;

if (options.Rate.HasValue)
ss.Rate = options.Rate.Value;
}

ssd.FinishedSpeaking += OnFinishedSpeaking;
Expand Down
16 changes: 16 additions & 0 deletions src/Essentials/src/TextToSpeech/TextToSpeech.shared.cs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,10 @@ partial class TextToSpeechImplementation : ITextToSpeech
internal const float VolumeDefault = 0.5f;
internal const float VolumeMin = 0.0f;

internal const float RateMax = 2.0f;
internal const float RateDefault = 1.0f;
internal const float RateMin = 0.1f;

SemaphoreSlim? semaphore;

public Task<IEnumerable<Locale>> GetLocalesAsync() =>
Expand All @@ -170,6 +174,12 @@ public async Task SpeakAsync(string text, SpeechOptions? options = default, Canc
throw new ArgumentOutOfRangeException($"Pitch must be >= {PitchMin} and <= {PitchMin}");
}

if (options?.Rate.HasValue ?? false)
{
if (options.Rate.Value < RateMin || options.Rate.Value > RateMax)
throw new ArgumentOutOfRangeException($"Rate must be >= {RateMin} and <= {RateMin}");
}

if (semaphore == null)
semaphore = new SemaphoreSlim(1, 1);

Expand Down Expand Up @@ -245,5 +255,11 @@ public class SpeechOptions
/// </summary>
/// <remarks>This value should be between <c>0f</c> and <c>1.0f</c>.</remarks>
public float? Volume { get; set; }

/// <summary>
/// The speech rate to use when speaking.
/// </summary>
/// <remarks>This value should be between <c>0.1f</c> and <c>2.0f</c>.</remarks>
public float? Rate { get; set; }
}
}
8 changes: 4 additions & 4 deletions src/Essentials/src/TextToSpeech/TextToSpeech.tizen.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,11 @@ async Task PlatformSpeakAsync(string text, SpeechOptions options, CancellationTo
}
}

var pitch = 0;
if (options?.Pitch.HasValue ?? false)
pitch = (int)Math.Round(options.Pitch.Value / PitchMax * tts.GetSpeedRange().Max, MidpointRounding.AwayFromZero);
var rate = 0;
if (options?.Rate.HasValue ?? false)
rate = (int)Math.Round(options.Rate.Value / RateMax * tts.GetSpeedRange().Max, MidpointRounding.AwayFromZero);

tts.AddText(text, language, (int)voiceType, pitch);
tts.AddText(text, language, (int)voiceType, rate);
tts.Play();

await tcsUtterances.Task;
Expand Down
5 changes: 4 additions & 1 deletion src/Essentials/src/TextToSpeech/TextToSpeech.uwp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ static string GetSpeakParametersSSMLProsody(string text, SpeechOptions options)
{
var volume = "default";
var pitch = "default";
var rate = "default";
var rate = "medium";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A bit unrelated but perhaps this is a good opportunity to rename:

src/Essentials/src/TextToSpeech/TextToSpeech.uwp.cs
->
src/Essentials/src/TextToSpeech/TextToSpeech.Windows.cs

as that is the preferred name here. See https://github.com/search?q=repo%3Adotnet%2Fmaui%20.windows.cs&type=code.


// Look for the specified language, otherwise the default voice
var locale = options?.Locale?.Language ?? SpeechSynthesizer.DefaultVoice.Language;
Expand All @@ -82,6 +82,9 @@ static string GetSpeakParametersSSMLProsody(string text, SpeechOptions options)
if (options?.Pitch.HasValue ?? false)
pitch = ProsodyPitch(options.Pitch);

if (options?.Rate.HasValue ?? false)
rate = (options.Rate.Value * 100f).ToString(CultureInfo.InvariantCulture)+"%";

// SSML generation
var ssml = new StringBuilder();
ssml.AppendLine($"<speak version='1.0' xmlns='http://www.w3.org/2001/10/synthesis' xml:lang='{locale}'>");
Expand Down
Loading