Skip to content

Commit 7bdad5d

Browse files
Merge pull request #72 from nullinside-development-group/feat/speed
feat: exposing underlying sound stretch variables
2 parents 0f785c4 + 9e09928 commit 7bdad5d

File tree

8 files changed

+307
-6
lines changed

8 files changed

+307
-6
lines changed

src/TwitchStreamingTools/Configuration.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,11 @@ public static Configuration Instance {
7878
/// </summary>
7979
public IDictionary<string, string>? TtsPhonetics { get; set; }
8080

81+
/// <summary>
82+
/// The arguments to pass to Sound Stretcher to manipulate the TTS audio.
83+
/// </summary>
84+
public SoundStretchArgs? SoundStretchArgs { get; set; }
85+
8186
/// <summary>
8287
/// Writes the configuration file to disk.
8388
/// </summary>

src/TwitchStreamingTools/IConfiguration.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ public interface IConfiguration {
4040
/// </summary>
4141
IDictionary<string, string>? TtsPhonetics { get; set; }
4242

43+
/// <summary>
44+
/// The arguments to pass to sound stretch to manipulate TTS audio.
45+
/// </summary>
46+
SoundStretchArgs? SoundStretchArgs { get; set; }
47+
4348
/// <summary>
4449
/// Writes the configuration file to disk.
4550
/// </summary>
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
namespace TwitchStreamingTools.Models;
2+
3+
/// <summary>
4+
/// The arguments to pass to sound stretcher when manipulating TTS audio.
5+
/// </summary>
6+
public class SoundStretchArgs {
7+
/// <summary>
8+
/// Change sound tempo by n percents (-95 to +5000 %)
9+
/// </summary>
10+
public int? Tempo { get; set; }
11+
12+
/// <summary>
13+
/// Change sound pitch by n semitones (-60 to +60 semitones)
14+
/// </summary>
15+
public int? Pitch { get; set; }
16+
17+
/// <summary>
18+
/// Change sound rate by n percents (-95 to +5000 %)
19+
/// </summary>
20+
public int? Rate { get; set; }
21+
22+
/// <summary>
23+
/// Detect the BPM rate of sound and adjust tempo to meet 'n' BPMs. If value not specified, just detects the BPM rate.
24+
/// </summary>
25+
public int? Bpm { get; set; }
26+
27+
/// <summary>
28+
/// Use quicker tempo change algorithm (gain speed, lose quality)
29+
/// </summary>
30+
public bool Quick { get; set; }
31+
32+
/// <summary>
33+
/// Don't use anti-alias filtering (gain speed, lose quality)
34+
/// </summary>
35+
public bool AntiAliasingOff { get; set; }
36+
37+
/// <summary>
38+
/// Tune algorithm for speech processing (default is for music)
39+
/// </summary>
40+
public bool TurnOnSpeech { get; set; }
41+
}

src/TwitchStreamingTools/Tts/TwitchChatTts.cs

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Diagnostics;
44
using System.IO;
55
using System.Speech.Synthesis;
6+
using System.Text;
67
using System.Threading;
78

89
using NAudio.Wave;
@@ -233,7 +234,7 @@ private void PlaySoundsThread() {
233234
private void InitializeAndPlayTts(string sender, string chatMessage) {
234235
string filename = Path.GetTempFileName();
235236
string filename2 = Path.GetTempFileName();
236-
237+
237238
try {
238239
string fileToPlay = filename;
239240

@@ -255,7 +256,7 @@ private void InitializeAndPlayTts(string sender, string chatMessage) {
255256

256257
var startInfo = new ProcessStartInfo {
257258
FileName = @"3rdParty\soundstretch.exe",
258-
Arguments = $"\"{filename}\" \"{filename2}\" -tempo=+100 -speech",
259+
Arguments = $"\"{filename}\" \"{filename2}\" {GetSoundStretcherArgs()}",
259260
UseShellExecute = false,
260261
CreateNoWindow = true
261262
};
@@ -364,4 +365,41 @@ private void Client_OnMessageReceived(OnMessageReceivedArgs e) {
364365
Console.WriteLine($"Failed to add: {e.ChatMessage.Username} says {e.ChatMessage.Message}\r\n{ex}");
365366
}
366367
}
368+
369+
/// <summary>
370+
/// Converts the configuration arguments to command line arguments for sound stretcher.
371+
/// </summary>
372+
/// <returns>The command line arguments.</returns>
373+
private string GetSoundStretcherArgs() {
374+
StringBuilder sb = new();
375+
if (null != _configuration.SoundStretchArgs?.Tempo) {
376+
sb.Append($" -tempo={(_configuration.SoundStretchArgs.Tempo > 0 ? "+" : "")}{_configuration.SoundStretchArgs.Tempo}");
377+
}
378+
379+
if (null != _configuration.SoundStretchArgs?.Pitch) {
380+
sb.Append($" -pitch={(_configuration.SoundStretchArgs.Pitch > 0 ? "+" : "")}{_configuration.SoundStretchArgs.Pitch}");
381+
}
382+
383+
if (null != _configuration.SoundStretchArgs?.Rate) {
384+
sb.Append($" -rate={(_configuration.SoundStretchArgs.Rate > 0 ? "+" : "")}{_configuration.SoundStretchArgs.Rate}");
385+
}
386+
387+
if (null != _configuration.SoundStretchArgs?.Bpm) {
388+
sb.Append($" -bpm={_configuration.SoundStretchArgs.Bpm}");
389+
}
390+
391+
if (_configuration.SoundStretchArgs?.Quick ?? false) {
392+
sb.Append(" -quick");
393+
}
394+
395+
if (_configuration.SoundStretchArgs?.AntiAliasingOff ?? false) {
396+
sb.Append(" -naa");
397+
}
398+
399+
if (_configuration.SoundStretchArgs?.TurnOnSpeech ?? false) {
400+
sb.Append(" -speech");
401+
}
402+
403+
return sb.ToString().Trim();
404+
}
367405
}

src/TwitchStreamingTools/ViewModels/Pages/SettingsView/SettingsViewModel.cs

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,36 @@ public class SettingsViewModel : PageViewModelBase {
1919
/// </summary>
2020
private readonly IConfiguration _configuration;
2121

22+
/// <summary>
23+
/// Don't use anti-alias filtering (gain speed, lose quality)
24+
/// </summary>
25+
private bool _antiAliasingOff;
26+
27+
/// <summary>
28+
/// Detect the BPM rate of sound and adjust tempo to meet 'n' BPMs. If value not specified, just detects the BPM rate.
29+
/// </summary>
30+
private int _bpm;
31+
2232
/// <summary>
2333
/// The list of possible output devices that exist on the machine.
2434
/// </summary>
2535
private ObservableCollection<string> _outputDevices;
2636

37+
/// <summary>
38+
/// Change sound pitch by n semitones (-60 to +60 semitones)
39+
/// </summary>
40+
private int _pitch;
41+
42+
/// <summary>
43+
/// Use quicker tempo change algorithm (gain speed, lose quality)
44+
/// </summary>
45+
private bool _quick;
46+
47+
/// <summary>
48+
/// Change sound rate by n percents (-95 to +5000 %)
49+
/// </summary>
50+
private int _rate;
51+
2752
/// <summary>
2853
/// The selected output device to send TTS to.
2954
/// </summary>
@@ -34,6 +59,11 @@ public class SettingsViewModel : PageViewModelBase {
3459
/// </summary>
3560
private string? _selectedTtsVoice;
3661

62+
/// <summary>
63+
/// Change sound tempo by n percents (-95 to +5000 %)
64+
/// </summary>
65+
private int _tempo;
66+
3767
/// <summary>
3868
/// The view model for the phonetic words list.
3969
/// </summary>
@@ -55,13 +85,19 @@ public class SettingsViewModel : PageViewModelBase {
5585
/// <remarks>0 is silent, 100 is full volume.</remarks>
5686
private uint _ttsVolume;
5787

88+
/// <summary>
89+
/// Tune algorithm for speech processing (default is for music)
90+
/// </summary>
91+
private bool _turnOnSpeech;
92+
5893
/// <summary>
5994
/// Initializes a new instance of the <see cref="SettingsViewModel" /> class.
6095
/// </summary>
6196
public SettingsViewModel(IConfiguration configuration, TtsPhoneticWordsViewModel ttsPhoneticWordsViewModel, TtsSkipUsernamesViewModel ttsSkipUsernamesViewModel) {
6297
_configuration = configuration;
6398
_ttsPhoneticWordsViewModel = ttsPhoneticWordsViewModel;
6499
_ttsSkipUsernamesViewModel = ttsSkipUsernamesViewModel;
100+
_configuration.SoundStretchArgs ??= new SoundStretchArgs();
65101

66102
// Get the list of output devices and set the default to either what we have in the configuration or the system
67103
// default whichever is more appropriate.
@@ -171,4 +207,102 @@ public TtsSkipUsernamesViewModel TtsSkipUsernamesViewModel {
171207
get => _ttsSkipUsernamesViewModel;
172208
set => this.RaiseAndSetIfChanged(ref _ttsSkipUsernamesViewModel, value);
173209
}
210+
211+
/// <summary>
212+
/// Change sound tempo by n percents (-95 to +5000 %)
213+
/// </summary>
214+
public int Tempo {
215+
get => _tempo;
216+
set {
217+
this.RaiseAndSetIfChanged(ref _tempo, value);
218+
if (_configuration.SoundStretchArgs != null) {
219+
_configuration.SoundStretchArgs.Tempo = value;
220+
_configuration.WriteConfiguration();
221+
}
222+
}
223+
}
224+
225+
/// <summary>
226+
/// Change sound pitch by n semitones (-60 to +60 semitones)
227+
/// </summary>
228+
public int Pitch {
229+
get => _pitch;
230+
set {
231+
this.RaiseAndSetIfChanged(ref _pitch, value);
232+
if (_configuration.SoundStretchArgs != null) {
233+
_configuration.SoundStretchArgs.Pitch = value;
234+
_configuration.WriteConfiguration();
235+
}
236+
}
237+
}
238+
239+
/// <summary>
240+
/// Change sound rate by n percents (-95 to +5000 %)
241+
/// </summary>
242+
public int Rate {
243+
get => _rate;
244+
set {
245+
this.RaiseAndSetIfChanged(ref _rate, value);
246+
if (_configuration.SoundStretchArgs != null) {
247+
_configuration.SoundStretchArgs.Rate = value;
248+
_configuration.WriteConfiguration();
249+
}
250+
}
251+
}
252+
253+
/// <summary>
254+
/// Detect the BPM rate of sound and adjust tempo to meet 'n' BPMs. If value not specified, just detects the BPM rate.
255+
/// </summary>
256+
public int Bpm {
257+
get => _bpm;
258+
set {
259+
this.RaiseAndSetIfChanged(ref _bpm, value);
260+
if (_configuration.SoundStretchArgs != null) {
261+
_configuration.SoundStretchArgs.Bpm = value;
262+
_configuration.WriteConfiguration();
263+
}
264+
}
265+
}
266+
267+
/// <summary>
268+
/// Use quicker tempo change algorithm (gain speed, lose quality)
269+
/// </summary>
270+
public bool Quick {
271+
get => _quick;
272+
set {
273+
this.RaiseAndSetIfChanged(ref _quick, value);
274+
if (_configuration.SoundStretchArgs != null) {
275+
_configuration.SoundStretchArgs.Quick = value;
276+
_configuration.WriteConfiguration();
277+
}
278+
}
279+
}
280+
281+
/// <summary>
282+
/// Don't use anti-alias filtering (gain speed, lose quality)
283+
/// </summary>
284+
public bool AntiAliasingOff {
285+
get => _antiAliasingOff;
286+
set {
287+
this.RaiseAndSetIfChanged(ref _antiAliasingOff, value);
288+
if (_configuration.SoundStretchArgs != null) {
289+
_configuration.SoundStretchArgs.AntiAliasingOff = value;
290+
_configuration.WriteConfiguration();
291+
}
292+
}
293+
}
294+
295+
/// <summary>
296+
/// Tune algorithm for speech processing (default is for music)
297+
/// </summary>
298+
public bool TurnOnSpeech {
299+
get => _turnOnSpeech;
300+
set {
301+
this.RaiseAndSetIfChanged(ref _turnOnSpeech, value);
302+
if (_configuration.SoundStretchArgs != null) {
303+
_configuration.SoundStretchArgs.TurnOnSpeech = value;
304+
_configuration.WriteConfiguration();
305+
}
306+
}
307+
}
174308
}

src/TwitchStreamingTools/ViewModels/Pages/SettingsView/TtsSkipUsernamesViewModel.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ private async void UserListRefreshTimer_OnElapsed(object sender, ElapsedEventArg
134134

135135
var usernames = new HashSet<string>();
136136
foreach (TwitchChatConfiguration chat in _configuration.TwitchChats ?? []) {
137-
if (string.IsNullOrWhiteSpace(chat.TwitchChannel)) {
137+
if (string.IsNullOrWhiteSpace(chat.TwitchChannel) || _doNotScanChat.Contains(chat.TwitchChannel)) {
138138
continue;
139139
}
140140

src/TwitchStreamingTools/Views/MainWindow.axaml.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
using Avalonia.Threading;
1212

1313
using TwitchStreamingTools.ViewModels;
14+
1415
#else
1516
using Avalonia;
1617
#endif

0 commit comments

Comments
 (0)