Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <pulse/error.h>
00023 #include <pulse/gccmacro.h>
00024 #include <pulse/simple.h>
00025
00026 #include <string>
00027
00028 #include "Config.h"
00029 #include "FestivalSynthesizer.h"
00030
00031 FestivalSynthesizer::FestivalSynthesizer() :
00032 festival_initialized_(false),
00033 synth_speech_(false),
00034 punctuation_characters_(0)
00035 {
00036 if (!festival_initialized_)
00037 {
00038 initFestival();
00039 festival_initialized_ = true;
00040 }
00041
00042 smileys_.push_back(">:");
00043 smileys_.push_back(":)");
00044 smileys_.push_back(":(");
00045 smileys_.push_back(":O");
00046 smileys_.push_back(":o");
00047 smileys_.push_back(":!");
00048 smileys_.push_back(":&");
00049
00050 punctuation_characters_.push_back(":");
00051 punctuation_characters_.push_back(")");
00052 punctuation_characters_.push_back("(");
00053 punctuation_characters_.push_back(".");
00054 punctuation_characters_.push_back("'");
00055 punctuation_characters_.push_back("\"");
00056 punctuation_characters_.push_back("}");
00057 punctuation_characters_.push_back("{");
00058 punctuation_characters_.push_back("§");
00059 punctuation_characters_.push_back("!");
00060 punctuation_characters_.push_back("?");
00061 punctuation_characters_.push_back("`");
00062 punctuation_characters_.push_back("´");
00063 punctuation_characters_.push_back("-");
00064 punctuation_characters_.push_back(";");
00065 punctuation_characters_.push_back(",");
00066 punctuation_characters_.push_back("€");
00067 punctuation_characters_.push_back("°");
00068 punctuation_characters_.push_back("<");
00069 punctuation_characters_.push_back(">");
00070 punctuation_characters_.push_back(".");
00071 }
00072
00073 FestivalSynthesizer::~FestivalSynthesizer()
00074 {
00075 festival_tidy_up();
00076 }
00077
00078 void FestivalSynthesizer::initFestival()
00079 {
00080 int heap_size = 210000;
00081 int load_init_files = 1;
00082
00083 festival_initialize(load_init_files, heap_size);
00084
00085 try
00086 {
00087 const char* cfgFilename = "../config.cfg";
00088
00089 Config cfg(cfgFilename);
00090 std::string voice = cfg.get("Voice");
00091
00092 if ( voice == "female" )
00093 {
00094 festival_eval_command( "(voice_us1_mbrola)" );
00095 festival_eval_command( "(defvar Styles '((default 140 22 1.0)) \"Available voice styles\")" );
00096 festival_eval_command( "(defvar style_default 'default \"Default voice style\")" );
00097 festival_eval_command( "(defvar current_style 'none \"Current voice style\")" );
00098 festival_eval_command( "(define (Style selected_style) (let ((style (assoc selected_style Styles)))"
00099 "(if (not style) (set! style (assoc 'default Styles)))"
00100 "(let ((model_mean (cadr (assoc 'model_f0_mean int_lr_params)))"
00101 "(model_std (cadr (assoc 'model_f0_std int_lr_params)))"
00102 "(new_mean (cadr style)) (new_std (cadr (cdr style)))"
00103 "(new_stretch (cadr (cdr (cdr style)))))"
00104 "(set! int_lr_params (list (list 'target_f0_mean new_mean)"
00105 "(list 'target_f0_std new_std) (list 'model_f0_mean model_mean)"
00106 "(list 'model_f0_std model_std)))"
00107 "(Parameter.set 'Duration_Stretch new_stretch)"
00108 "(set! current_style (car style)) (list (car style) new_mean new_std new_stretch) ) ) )" );
00109 festival_eval_command( "(define (NewStyle style_name mean std stretch)"
00110 "(set! Styles (cons (list style_name mean std stretch) Styles)))" );
00111 festival_eval_command( "(NewStyle 'lisa 280 50 1.2)" );
00112 festival_eval_command( "(Style 'lisa)" );
00113 }
00114 }
00115 catch(const std::exception& e)
00116 {
00117 std::cerr << e.what() << std::endl;
00118 }
00119
00120
00121 EST_Wave wave;
00122 festival_text_to_wave( "init", wave );
00123
00124
00125 pa_sample_spec sample_spec;
00126 sample_spec.format = PA_SAMPLE_S16NE;
00127 sample_spec.channels = 1;
00128 sample_spec.rate = wave.sample_rate();
00129
00130 pa_simple_ = pa_simple_new( NULL,
00131 "FestivalSynthesizer",
00132 PA_STREAM_PLAYBACK,
00133 NULL,
00134 "Festival Synthesizer (TalkingHead)",
00135 &sample_spec,
00136 NULL,
00137 NULL,
00138 NULL
00139 );
00140
00141 if ( !pa_simple_ )
00142 {
00143 ROS_ERROR ( "Error initializing PulseAudio!" );
00144 }
00145 }
00146
00147 void FestivalSynthesizer::run()
00148 {
00149 ros::NodeHandle node_handle;
00150 subscriber_ = node_handle.subscribe( "robot_face/text_out", 1, &FestivalSynthesizer::callbackSynth, this );
00151
00152
00153 talking_finished_publisher_ = node_handle.advertise<std_msgs::String>( "robot_face/talking_finished", 1 );
00154
00155 while( ros::ok() )
00156 {
00157 ros::getGlobalCallbackQueue()->callOne( ros::WallDuration( 3 ) );
00158
00159 if( synth_speech_ )
00160 {
00161 synthSpeech( text_for_synth_ );
00162 festival_wait_for_spooler();
00163
00164 std_msgs::String msg;
00165
00166 std::stringstream string_stream;
00167 string_stream << "talking_finished";
00168 msg.data = string_stream.str();
00169
00170 talking_finished_publisher_.publish( msg );
00171
00172 synth_speech_ = false;
00173 }
00174 }
00175 }
00176
00177 void FestivalSynthesizer::callbackSynth( const std_msgs::String::ConstPtr& msg )
00178 {
00179 text_for_synth_ = prepareText( msg->data );
00180 if( text_for_synth_.length() > 0 )
00181 {
00182 synth_speech_ = true;
00183 }
00184 }
00185
00186 void FestivalSynthesizer::synthSpeech ( std::string text )
00187 {
00188 if ( pa_simple_ )
00189 {
00190 EST_Wave wave;
00191 festival_text_to_wave( text.c_str(), wave );
00192 int error;
00193 pa_simple_write( pa_simple_, &(wave.a(0)), wave.length()*2, &error );
00194 }
00195 else
00196 {
00197 ROS_ERROR( "Cannot snyth speec. Initilization failed." );
00198 }
00199 }
00200
00201 std::string FestivalSynthesizer::prepareText( std::string text )
00202 {
00203 std::string tmp_text = text;
00204
00205 tmp_text = trimSpaces( tmp_text );
00206 tmp_text = clearSmileys( tmp_text );
00207
00208 size_t i_symbol = std::string::npos;
00209
00210 for( unsigned int j = 0; j < punctuation_characters_.size(); j++ )
00211 {
00212 for( unsigned int i = 0; i < tmp_text.length(); i++ )
00213 {
00214 i_symbol = tmp_text.find( punctuation_characters_.at( j ), 0 );
00215 if( i_symbol != std::string::npos )
00216 {
00217 tmp_text.erase(i_symbol, punctuation_characters_.at( j ).length());
00218 }
00219 }
00220 }
00221 tmp_text = trimSpaces( tmp_text );
00222
00223 return tmp_text;
00224 }
00225
00226 std::string FestivalSynthesizer::clearSmileys( std::string text )
00227 {
00228 std::string tmp_text = text;
00229
00230 size_t i_smiley = std::string::npos;
00231
00232 for( unsigned int j = 0; j < smileys_.size(); j++ )
00233 {
00234 for( unsigned int i = 0; i < tmp_text.length(); i++ )
00235 {
00236 i_smiley = tmp_text.find( smileys_.at( j ), 0 );
00237 if( i_smiley != std::string::npos )
00238 {
00239 tmp_text.erase(i_smiley, smileys_.at( j ).length());
00240 }
00241 }
00242 }
00243
00244 return tmp_text;
00245 }
00246
00247 std::string FestivalSynthesizer::trimSpaces( std::string text )
00248 {
00249 std::string tmp_text = text;
00250
00251 size_t startpos = tmp_text.find_first_not_of(" \t");
00252 size_t endpos = tmp_text.find_last_not_of(" \t");
00253
00254 if(( std::string::npos == startpos ) || ( std::string::npos == endpos))
00255 {
00256 tmp_text = "";
00257 }
00258 else
00259 {
00260 tmp_text = tmp_text.substr( startpos, endpos-startpos+1 );
00261 }
00262
00263 return tmp_text;
00264 }
00265
00266 int main( int argc, char *argv[] )
00267 {
00268 ros::init(argc, argv, "FestivalSynthesizer");
00269 FestivalSynthesizer fs;
00270 fs.run();
00271
00272 return 0;
00273 }