Increase number of player speed settings

Dear all,
Please increase the number of possible speed settings in the HTML5 player.
IncreasedNumberOfPlayerSpeeds
This would allow better adaption for “hurried native speakers: come on, get to the point”, “tired standard users: just a litte bit slower” as well as “beginners in this language”.
We ran tests with many different kind of people and settled with a default speed of 40 and the increments shown above. Currently, we a tweak the player code after generation to have this feature. :wink:
I think it would be only a small effort to increase the number of increments or provide a slider mit central default position.
Best regards,
Martin

2 Likes

Hi,

Thank you for your feedback.

We will add this feature in our TODO list. But, I am not sure if it will be available soon since there are many other tasks with higher priorities.

Regards,

I want to add another aspect: the standard TTS-voices in Win10 allow to adjust the speed before generating. When using cloud-based NeuralVoices the controls are blocked, so they always run on original speed which is too fast for non-native speakers. Therefore, there is a much higher demand for a online-speed adjustment in fine steps.

Any chance to get this tiny, but powerful feature squeezed in an up-coming release?

Hi,

For cloud TTS voices, you can use SSML tags to add pauses and other speech effects such as emphasis, volume, speaking rate, pitch, and more to that voice.
For example, if you want to adjust the voice speed, you can use the <prosody> tag to adjust the speaking rate as you wish.

Please refer to the Use SSML Tags section at the end of this tutorial for more information:
Get More Text-to-Speech Voices from the Third Parties - ActivePresenter 8 (atomisystems.com)

Regards,

But is again a general setting for all users. We urgently need the possibility for an individual fine tuning of speed during training consumption due to the wide variety of the language skills of our users (from native speakers: “hurry up, get to the point” to beginners in contents and in language: “I do not understand, could you speek slower, please”).

Hi Martin,

We will improve it in future releases. It is quite useful for normal users that they want to change the speed and volume quickly.

Regards,

I would like to upvote this Feature Request. The current settings are too big of a jump in speed changes.

Martin, would you be willing to post the code for how you implemented the additional speed changes?

Thanks
Keith

I would, but my patch program (written in C#) doesn’t work anymore. Without really understanding JS and CSS I changed the ‘suspicous’ spots in various files in the V7 player and it worked. When V8 came up, I tried to adapt it to the new player, but for some reasons I could not get it to run again.
Maybe someone with more knowledge in web-technology could solve that easily.
Shall I post my C# code nevertheless?

I post my code anyhow. Maybe it might help someelse to implement it properly in the web-world:

      string PlayerFolder = Path.Combine(WebFolder, "player");

      double[] Speeds = { 0.50, 0.67, 0.80, 0.90, 0.95, 1.00, 1.05, 1.10, 1.25, 1.5, 2.0 };// {0.33, 0.5, 0.66, 1.0, 1.5, 2.0, 3.0 }; 
      EnhanceVariableAudioSpeed(PlayerFolder, Speeds);
#region EnhancePlayer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

public static void EnhanceVariableAudioSpeed(string TestFolder, double[] Speeds)
{
  _logger.Trace($"Enhancing variable audio speed ...");
  EnhanceCSS(TestFolder, Speeds);
  EnhanceJS(TestFolder, Speeds);
  EnhanceLang(TestFolder);
}

private const string JsFileName = "rlplayer.js";
private static void EnhanceJS(string TestFolder, double[] Speeds)
{
  string JsFile = Path.Combine(TestFolder, JsFileName);
  string JsTextOld = File.ReadAllText(JsFile);
  string JsTextNew = JsTextOld;

  string PatFrom = "ap-tool-speed_0_5";
  string PatTo = "ap-tool-speed_2_0";
  var MFrom = Regex.Matches(JsTextOld, PatFrom);
  var MTo = Regex.Matches(JsTextOld, PatTo);

  // i(".ap-tool-speed_1_0",h).on("click",function(){i(e).trigger("ui:ap-speed",[1])}),
  int ClickOnIxFrom = MFrom[0].Index - 4;
  int ClickOnIxTo = JsTextOld.IndexOf("})", MTo[0].Index) + 2;
  string ClickOnOld = JsTextOld.Substring(ClickOnIxFrom, ClickOnIxTo - ClickOnIxFrom);
  List<string> ClickOnList = new List<string>();
  foreach (var s in Speeds)
  {
    ClickOnList.Add($"i(\".ap-tool-speed_{AsName(s)}\",h).on(\"click\",function(){{i(e).trigger(\"ui:ap-speed\",[{AsDouble(s)}])}})");
  }
  string ClickOnNew = String.Join(",", ClickOnList);
  FixJavaScript(ref JsTextNew, ClickOnOld, ClickOnNew, "onClick");

  // i(".ap-tool-speed_1_0",s).off("click"),
  int ClickOffIxFrom = MFrom[1].Index - 4;
  int ClickOffIxTo = JsTextOld.IndexOf("),", MTo[1].Index) + 1;
  string ClickOffOld = JsTextOld.Substring(ClickOffIxFrom, ClickOffIxTo - ClickOffIxFrom);
  List<string> ClickOffList = new List<string>();
  foreach (var s in Speeds)
  {
    ClickOffList.Add($"i(\".ap-tool-speed_{AsName(s)}\",s).off(\"click\")");
  }
  string ClickOffNew = String.Join(",", ClickOffList);
  FixJavaScript(ref JsTextNew, ClickOffOld, ClickOffNew, "offClick");

  // s.addRadioMenuItem("ap-tool-speed_1_0","1.0x",1==e),
  int Menu1IxFrom = MFrom[2].Index - 18;
  int Menu1IxTo = JsTextOld.IndexOf("e)", MTo[2].Index) + 2;
  string Menu1Old = JsTextOld.Substring(Menu1IxFrom, Menu1IxTo - Menu1IxFrom);
  List<string> Menu1List = new List<string>();
  foreach (var s in Speeds)
  {
    Menu1List.Add($"s.addRadioMenuItem(\"ap-tool-speed_{AsName(s)}\",\"{AsDouble(s)}x\",{AsDouble(s)}==e)");
  }
  string Menu1New = String.Join(",", Menu1List);
  Menu1New = Menu1New.Substring(2); // skip first "s."
  FixJavaScript(ref JsTextNew, Menu1Old, Menu1New, "addMenuItem");

  // l.addRadioMenuItem("ap-tool-speed_1_0","1.0x",1==r),
  int Menu2IxFrom = MFrom[3].Index - 20;
  int Menu2IxTo = JsTextOld.IndexOf("r)", MTo[3].Index) + 2;
  string Menu2Old = JsTextOld.Substring(Menu2IxFrom, Menu2IxTo - Menu2IxFrom);
  string Menu2New = Menu1New.Replace("s.add", "l.add").Replace("= e", "= r");
  FixJavaScript(ref JsTextNew, Menu2Old, Menu2New, "case addMenuItem");

  // .5,1,1.5,2
  string ArrayOld = ".5,1,1.5,2";
  string ArrayNew = String.Join(",", Speeds.Select(s => AsDouble(s)));
  FixJavaScript(ref JsTextNew, ArrayOld, ArrayNew, "array of speeds");

  // "speed05", "speed10", "speed15", "speed20"
  string SpeedArrayOld = "\"speed05\",\"speed10\",\"speed15\",\"speed20\"";
  string SpeedArrayNew = String.Join(",", Speeds.Select(s => $"\"speed10\"")); //.Select(s => $"\"speed{AsName(s)}\""));
  //string SpeedArrayNew = String.Join(",", Speeds.Select(s => $"\"speed{AsName(s)}\""));
  FixJavaScript(ref JsTextNew, SpeedArrayOld, SpeedArrayNew, "speed texts");

  File.WriteAllText(JsFile, JsTextNew);
}

private static void FixJavaScript(ref string JsText, string OldText, string NewText, string CodeName, string PlayerFile = JsFileName)
{
  if (JsText.Contains(OldText))
  {
    JsText = JsText.Replace(OldText, NewText);
  }
  else
  {
    _logger.Error($"Could not fix {CodeName} code in {JsFileName}."); 
  }
}

private static string MinifyCss(string CssText)
{
  CssText = CssText.Replace("\r\n", "");
  CssText = CssText.Replace("\t", "");
  return CssText;
}


private const string CssFileName = "rlplayer.css";
private static void EnhanceCSS(string TestFolder, double[] Speeds)
{
  string CssFile = Path.Combine(TestFolder, CssFileName);
  string OldFrom = @".ap-button.ap-tool-speed";
  string OldTo = @".ap-button.ap-tool-sound";

  string CssText = File.ReadAllText(CssFile);
  //CssText = MinifyCss(CssText);
  var MatchFrom = Regex.Match(CssText, OldFrom);
  var MatchTo = Regex.Match(CssText, OldTo);
  string OldText = CssText.Substring(MatchFrom.Index, MatchTo.Index - MatchFrom.Index);

  StringBuilder SB = new StringBuilder();
  SB.AppendLine(".ap-button.ap-tool-speed svg {	display: block;}");
  for (int i = 0; i < Speeds.Count(); i++)
  {
    SB.AppendLine($".ap-button.ap-tool-speed[data-value=\"{Speeds[i].ToString("0.00").Replace(",", ".")}\"] svg:nth-child({i + 1}){{ display: block;}}");
  }
  SB.AppendLine();
  string NewText = SB.ToString();
  FixJavaScript(ref CssText, OldText, NewText, "player button options", CssFileName);

  File.WriteAllText(CssFile, CssText);

}

private static void EnhanceLang(string TestFolder)
{
  string JsFile = Path.Combine(TestFolder, "rlplayer.lang.en-US.js");
  string OldText = "Click or tap to unmute";
  string NewText = "Click or tap to unmute. Adapt playback speed to your needs.";

  string JsText = File.ReadAllText(JsFile);
  if (Regex.IsMatch(JsText, OldText))
  {
    JsText = JsText.Replace(OldText, NewText);
  }
  else
  {
    _logger.Error($"Could not modify language file. ");
  }
  File.WriteAllText(JsFile, JsText);
}

private static string AsName(double s)
{
  return s.ToString("0.00").Replace(",", "_").Replace(".", "_");
}

private static string AsDouble(double s)
{
  return s.ToString("0.00").Replace(",", ".");
}
#endregion EnhancePlayer ----------------------------------------------------------------------------------------------

Would be really cool!

Hi,

There is a faster workaround for this problem in version 8.5. You can edit the list of playback speeds in the file:
C:\Program Files\ATOMI\ActivePresenter\templates\html5\js\rlprez.js at the following line:

d.playbackRates = [ 0.5, 1.0, 1.5, 2.0, 3.0, 4.0 ];

then export the project again.

Regards,

Dear ActivePresenter team,
thanks a lot for enabling this feature. Even in this short time I received a lot of very positive feedback from my colleagues in our company which I want to pass on to you.
Best regards,
Martin

1 Like