1 /* Copyright (C) 2012, 2013, 2018 Olga Yakovleva <yakovleva.o.v@gmail.com> */
2
3 /* This program is free software: you can redistribute it and/or modify */
4 /* it under the terms of the GNU General Public License as published by */
5 /* the Free Software Foundation, either version 2 of the License, or */
6 /* (at your option) any later version. */
7
8 /* This program is distributed in the hope that it will be useful, */
9 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
10 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
11 /* GNU General Public License for more details. */
12
13 /* You should have received a copy of the GNU General Public License */
14 /* along with this program. If not, see <http://www.gnu.org/licenses/>. */
15
16 #include <memory>
17 #include <stdexcept>
18 #include <iostream>
19 #include <fstream>
20 #include <iterator>
21 #include <algorithm>
22
23 #ifdef WITH_CLI11
24 #include <CLI/CLI.hpp>
25 #else
26 #include "tclap/CmdLine.h"
27 #endif
28
29 #include "core/engine.hpp"
30 #include "core/document.hpp"
31 #include "core/client.hpp"
32 #include "audio.hpp"
33
34 using namespace RHVoice;
35
36 namespace
37 {
38 class audio_player: public client
39 {
40 public:
41 explicit audio_player(const std::string& path);
42 bool play_speech(const short* samples,std::size_t count);
43 void finish();
44 bool set_sample_rate(int sample_rate);
45 bool set_buffer_size(unsigned int buffer_size);
46
47 private:
48 audio::playback_stream stream;
49 };
50
audio_player(const std::string & path)51 audio_player::audio_player(const std::string& path)
52 {
53 if(!path.empty())
54 {
55 stream.set_backend(audio::backend_file);
56 stream.set_device(path);
57 }
58 }
59
set_sample_rate(int sample_rate)60 bool audio_player::set_sample_rate(int sample_rate)
61 {
62 try
63 {
64 if(stream.is_open()&&(stream.get_sample_rate()!=sample_rate))
65 stream.close();
66 stream.set_sample_rate(sample_rate);
67 return true;
68 }
69 catch(...)
70 {
71 return false;
72 }
73 }
74
set_buffer_size(unsigned int buffer_size)75 bool audio_player::set_buffer_size(unsigned int buffer_size)
76 {
77 try
78 {
79 if(stream.is_open()&&(stream.get_buffer_size()!=buffer_size))
80 stream.close();
81 stream.set_buffer_size(buffer_size);
82 return true;
83 }
84 catch(...)
85 {
86 return false;
87 }
88 }
89
play_speech(const short * samples,std::size_t count)90 bool audio_player::play_speech(const short* samples,std::size_t count)
91 {
92 try
93 {
94 if(!stream.is_open())
95 stream.open();
96 stream.write(samples,count);
97 return true;
98 }
99 catch(...)
100 {
101 stream.close();
102 return false;
103 }
104 }
105
finish()106 void audio_player::finish()
107 {
108 if(stream.is_open())
109 stream.drain();
110 }
111 }
112
113 #ifdef WITH_CLI11
114 typedef CLI::App AppT;
115 #define GET_CLI_PARAM_VALUE(NAME) (NAME ## Stor)
116 #else
117 typedef TCLAP::CmdLine AppT;
118 #define GET_CLI_PARAM_VALUE(NAME) (NAME).getValue()
119 #endif
120
121
122
123
main(int argc,const char * argv[])124 int main(int argc,const char* argv[])
125 {
126 try{
127 AppT cmd("Simple test of the synthesizer");
128
129 #ifdef WITH_CLI11
130 std::string inpath_argStor {"-"};
131 auto inpath_arg = cmd.add_option("-i,--input",inpath_argStor,"input file","path");
132 std::string outpath_argStor {""};
133 auto outpath_arg = cmd.add_option("-o,--output",outpath_argStor,"output file","path");
134 bool ssml_switchStor = false;
135 auto ssml_switch = cmd.add_option("-s,--ssml",ssml_switchStor,"Process as ssml");
136 std::string voice_argStor{""};
137 auto voice_arg = cmd.add_option("-p,--profile",voice_argStor,"voice profile","spec");
138 unsigned int rate_argStor = 100;
139 auto rate_arg = cmd.add_option("-r,--rate",rate_argStor,"speech rate","percent");
140 uint32_t sample_rateStor = 24000;
141 auto sample_rate = cmd.add_option("-R,--sample-rate",sample_rateStor,"sample rate","Hz");
142 unsigned int pitch_argStor = 100;
143 auto pitch_arg = cmd.add_option("-t,--pitch",pitch_argStor,"speech pitch","percent");
144 unsigned int volume_argStor = 100;
145 auto volume_arg = cmd.add_option("-v,--volume",volume_argStor,"speech volume","percent");
146 cmd.allow_windows_style_options();
147 #else
148 TCLAP::ValueArg<std::string> inpath_arg("i","input","input file",false,"-","path",cmd);
149 TCLAP::ValueArg<std::string> outpath_arg("o","output","output file",false,"","path",cmd);
150 TCLAP::SwitchArg ssml_switch("s","ssml","Process as ssml",cmd,false);
151 TCLAP::ValueArg<std::string> voice_arg("p","profile","voice profile",false,"","spec",cmd);
152 TCLAP::ValueArg<unsigned int> rate_arg("r","rate","speech rate",false,100,"percent",cmd);
153 TCLAP::ValueArg<uint32_t> sample_rate("R","sample-rate","sample rate",false, 24000,"Hz",cmd);
154 TCLAP::ValueArg<unsigned int> pitch_arg("t","pitch","speech pitch",false,100,"percent",cmd);
155 TCLAP::ValueArg<unsigned int> volume_arg("v","volume","speech volume",false,100,"percent",cmd);
156 #endif
157
158 #ifdef WITH_CLI11
159 try{
160 #endif
161 cmd.parse(argc,argv);
162 #ifdef WITH_CLI11
163 }catch (const CLI::ParseError &e) {
164 return cmd.exit(e);
165 }
166 #endif
167
168 std::ifstream f_in;
169 if(GET_CLI_PARAM_VALUE(inpath_arg)!="-")
170 {
171 f_in.open(GET_CLI_PARAM_VALUE(inpath_arg).c_str());
172 if(!f_in.is_open())
173 throw std::runtime_error("Cannot open the input file");
174 }
175 audio_player player(GET_CLI_PARAM_VALUE(outpath_arg));
176 player.set_sample_rate(GET_CLI_PARAM_VALUE(sample_rate));
177 player.set_buffer_size(20);
178 std::shared_ptr<engine> eng(new engine);
179 voice_profile profile;
180 if(!GET_CLI_PARAM_VALUE(voice_arg).empty())
181 profile=eng->create_voice_profile(GET_CLI_PARAM_VALUE(voice_arg));
182 std::istreambuf_iterator<char> text_start(f_in.is_open()?f_in:std::cin);
183 std::istreambuf_iterator<char> text_end;
184 std::unique_ptr<document> doc;
185 if(GET_CLI_PARAM_VALUE(ssml_switch))
186 doc=document::create_from_ssml(eng,text_start,text_end,profile);
187 else
188 doc=document::create_from_plain_text(eng,text_start,text_end,content_text,profile);
189 doc->speech_settings.relative.rate=GET_CLI_PARAM_VALUE(rate_arg)/100.0;
190 doc->speech_settings.relative.pitch=GET_CLI_PARAM_VALUE(pitch_arg)/100.0;
191 doc->speech_settings.relative.volume=GET_CLI_PARAM_VALUE(volume_arg)/100.0;
192 doc->set_owner(player);
193 doc->synthesize();
194 player.finish();
195 return 0;
196 }
197 catch(const std::exception& e)
198 {
199 std::cerr << e.what() << std::endl;
200 return -1;
201 }
202 }
203