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