Skip to content

Commit bdb3cd5

Browse files
committed
Add voice speed.
1 parent 0897c0a commit bdb3cd5

File tree

4 files changed

+41
-7
lines changed

4 files changed

+41
-7
lines changed

libinclude/wsay/wsay.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,11 @@ struct voice {
4949
// Stop writing wave file.
5050
void stop_file_output();
5151

52-
5352
// Sets the voice volume, from 0 to 100.
5453
void set_volume(uint16_t volume);
5554

55+
// Sets the voice speed, from 0 to 100.
56+
void set_speed(uint16_t speed);
5657

5758
// Speaks the sentence using selected voice to playback outputs and file.
5859
// Blocking.

libsrc/wsay.cpp

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -134,19 +134,20 @@ bool parse_text_file(
134134

135135
struct voice_data {
136136
// Creates default voice.
137-
voice_data(ISpObjectToken* selected_voice, uint16_t vol) {
137+
voice_data(ISpObjectToken* selected_voice, uint16_t vol, int speed) {
138138
if (!SUCCEEDED(voice_ptr.CoCreateInstance(CLSID_SpVoice))) {
139139
throw std::runtime_error{ "Couldn't initialize voice." };
140140
}
141141

142142
voice_ptr->SetVoice(selected_voice);
143143
voice_ptr->SetVolume(vol);
144+
voice_ptr->SetRate(speed);
144145
}
145146

146147
// Creates file out voice.
147148
voice_data(ISpObjectToken* selected_voice,
148-
const std::filesystem::path& filepath, uint16_t vol)
149-
: voice_data(selected_voice, vol) {
149+
const std::filesystem::path& filepath, uint16_t vol, int speed)
150+
: voice_data(selected_voice, vol, speed) {
150151
path = filepath;
151152

152153
CComPtr<ISpStream> cpStream;
@@ -171,8 +172,8 @@ struct voice_data {
171172
}
172173

173174
voice_data(ISpObjectToken* selected_voice, size_t device_idx,
174-
ISpObjectToken* device, uint16_t vol)
175-
: voice_data(selected_voice, vol) {
175+
ISpObjectToken* device, uint16_t vol, int speed)
176+
: voice_data(selected_voice, vol, speed) {
176177

177178
device_playback_idx = device_idx;
178179
voice_ptr->SetOutput(device, TRUE);
@@ -203,7 +204,7 @@ struct voice_impl {
203204

204205
available_devices = get_playback_devices();
205206

206-
voices.push_back(voice_data{ nullptr, 100u });
207+
voices.push_back(voice_data{ nullptr, 100u, 0 });
207208
}
208209

209210
template <class Func>
@@ -229,6 +230,7 @@ struct voice_impl {
229230
std::vector<voice_data> voices;
230231
size_t selected_voice = 0;
231232
uint16_t volume = 100;
233+
int speed = 0;
232234
};
233235

234236

@@ -321,6 +323,7 @@ void voice::enable_device_playback(size_t device_idx) {
321323
device_idx,
322324
_impl->available_devices[device_idx].second,
323325
_impl->volume,
326+
_impl->speed,
324327
});
325328
}
326329

@@ -354,6 +357,7 @@ void voice::start_file_output(const std::filesystem::path& path) {
354357
_impl->available_voices[_impl->selected_voice].second,
355358
path,
356359
_impl->volume,
360+
_impl->speed,
357361
});
358362
}
359363

@@ -381,6 +385,17 @@ void voice::set_volume(uint16_t volume) {
381385
}
382386
}
383387

388+
void voice::set_speed(uint16_t speed) {
389+
speed = std::clamp(speed, uint16_t(0), uint16_t(100));
390+
double temp = (speed / 100.0) * 20.0;
391+
392+
_impl->speed = int(temp) - 10;
393+
394+
for (voice_data& v : _impl->voices) {
395+
v.voice_ptr->SetRate(_impl->speed);
396+
}
397+
}
398+
384399
void voice::speak(const std::wstring& sentence) {
385400
_impl->execute([&](CComPtr<ISpVoice>& voice) {
386401
voice->Speak(sentence.c_str(), SPF_DEFAULT | SPF_ASYNC, nullptr);

readme.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ Simple command line text-to-speech with easy file output, voice selection and mo
1717
- Note : Window's legacy command prompt has some of it's own issues with utf8.
1818
- If you need full unicode support, best to use the new [Windows Terminal](https://aka.ms/terminal).
1919
- Supports utf8, utf16le and utf16be text files.
20+
- Volume and speed options.
2021

2122

2223
## Install Instructions
@@ -84,11 +85,17 @@ wsay "I conquer all devices" -p all
8485
# You can set the voice volume, from 0 to 100.
8586
wsay "Softly speaking" --volume 25
8687

88+
# You can set the voice speed, from 0 to 100. 50 is the default speed.
89+
wsay "Quickly speaking" --speed 75
90+
8791
# Here, we are using voice 6, reading text from a file and outputting to 'output.wav'.
8892
wsay -v 6 -i mix_and_match_options.txt -o output.wav
8993

9094
# Ouput to multiple devices using interactive mode with voice 5.
9195
wsay -v 5 -I -p 1 2
96+
97+
# Speak slowly and quietly, on all devices, using voice 7 and save to wav file.
98+
wsay "Multiple options example." -v 7 -p all -s 25 -V 25 -o
9299
```
93100
94101
@@ -110,6 +117,7 @@ Options:
110117
You can provide more than 1 playback device, seperate the numbers with spaces. You
111118
can also mix output to file + playback.
112119
Use 'all' to select all devices.
120+
-s, --speed <value> Sets the voice speed, from 0 to 100. 50 is the default speed.
113121
-v, --voice <value> Choose a different voice. Use the voice number printed using --list_voices.
114122
-V, --volume <value> Sets the voice volume, from 0 to 100.
115123
-h, --help Print this help

src_cmd/main.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,16 @@ int wmain(int argc, wchar_t** argv, wchar_t**) {
171171
},
172172
L"Sets the voice volume, from 0 to 100.", L'V');
173173

174+
opt.add_required_arg_option(
175+
L"speed",
176+
[&](std::wstring&& f) {
177+
uint16_t speed = uint16_t(std::stoul(f));
178+
voice.set_speed(speed);
179+
return true;
180+
},
181+
L"Sets the voice speed, from 0 to 100. 50 is the default speed.",
182+
L's');
183+
174184
std::wstring help_outro = L"wsay\nversion ";
175185
help_outro += WSAY_VERSION;
176186
help_outro += L"\nhttps://github.com/p-groarke/wsay/releases\n";

0 commit comments

Comments
 (0)