【问题标题】:Android TTS fails to speak large amount of textAndroid TTS 无法朗读大量文字
【发布时间】:2013-10-19 04:52:21
【问题描述】:

我正在尝试使用 Android Text To Speech 说出大量文本。我使用默认的谷歌语音引擎。下面是我的代码。

 public class Talk extends Activity implements TextToSpeech.OnInitListener {

        private ImageView playBtn;

        private EditText textField;

        private TextToSpeech tts;
        private boolean isSpeaking = false;

        private String finalText;

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_talk);

            //Intialize the instance variables
            playBtn = (ImageView)findViewById(R.id.playBtn);

            textField = (EditText)findViewById(R.id.textField);


            //Resister the listeners
            playBtn.setOnClickListener(new PlayBtnAction());

            //Other things
            tts = new TextToSpeech(this,this);

            //Get the web page text if called from Share-Via
            if (Intent.ACTION_SEND.equals(getIntent().getAction())) 
            {

                   new GetWebText().execute("");

            }
        }


        //This class will execute the text from web pages
        private class GetWebText extends AsyncTask<String,Void,String>
        {

            @Override
            protected String doInBackground(String... params) {
                // TODO Auto-generated method stub
                String text = getIntent().getStringExtra(Intent.EXTRA_TEXT);
                String websiteText = "";


                 try {
                    //Create a URL for the desired page
                    URL url = new URL(text);
                    // Read all the text returned by the server
                    BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));
                    String str;
                    StringBuffer strBuffer = new StringBuffer("");

                    while ((str = in.readLine()) != null) 
                    {
                        strBuffer.append(str+"\n"+"\n");
                    }


                    in.close();

                    String html = strBuffer.toString();

                    Document doc = Jsoup.parse(html); 
                    websiteText = doc.body().text(); // "An example link"
                    //Toast.makeText(this, websiteText, Toast.LENGTH_LONG).show();

                 }
                 catch(Exception e)
                 {
                     Log.e("web_error", "Error in getting web text",e);
                 }
                return websiteText;
            }

            @Override
            protected void onPostExecute(String result)
            {
                textField.setText(result);
            }

        }

        }

        //Class to speak the text
            private class PlayBtnAction implements OnClickListener
            {


                @Override
                public void onClick(View v) 
                {

                    // TODO Auto-generated method stub
                    if(!isSpeaking)
                    {
                        isSpeaking = true;
                        //speak(textField.getText().toString());
                        finalText = textField.getText().toString();
                        new SpeakTheText().execute(finalText);
                        isSpeaking = false;
                    }
                    else
                    {
                        isSpeaking = false;
                        tts.stop();
                    }



                }

            }



        @Override
        public void onInit(int status) {
            // TODO Auto-generated method stub
            if(status==TextToSpeech.SUCCESS)
            {
                int result = tts.setLanguage(Locale.UK);

                if(result==TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED)
                {
                    Toast.makeText(this, "Language Not Supported", Toast.LENGTH_LONG).show();
                }
            }

        }


        //This class will speak the text
        private class SpeakTheText extends AsyncTask<String,Void,String>
        {

            @Override
            protected String doInBackground(String... params) {
                // TODO Auto-generated method stub
                tts.speak(params[0], TextToSpeech.QUEUE_FLUSH, null);
                return null;
            }

        }


          @Override
            public void onDestroy()
            {
                if(tts!=null)
                {
                    tts.stop();
                    tts.shutdown();

                }
                super.onDestroy();
            }

    }

但这里的问题是,当有大量文本时(假设您从网页中提取了文本),TTS 无法读取它。如果我删除大部分文本,那么它会阅读它。为什么会这样?

当我要阅读大文本时,LogCat 会显示类似这样的内容

10-11 07:26:05.566: D/dalvikvm(2638): GC_CONCURRENT freed 362K, 44% free 3597K/6312K, paused 17ms+8ms, total 93ms

【问题讨论】:

  • 如果块太大,你不能尝试更小的块吗?您可能已达到其队列限制。
  • @MorrisonChang:我必须阅读整个字符串。但是,我怎样才能得到小块?也许通过将字符串分成小字符串?
  • @Hope你有解决办法吗?

标签: java android eclipse text-to-speech google-text-to-speech


【解决方案1】:

字符串长度不应超过预定义的长度,来自docs:

参数

text 要朗读的文本字符串。不超过getMaxSpeechInputLength() 个字符。

getMaxSpeechInputLength() 的返回值可能因设备而异,但根据AOSP source,这是惊人的 4000

/**
 * Limit of length of input string passed to speak and synthesizeToFile.
 *
 * @see #speak
 * @see #synthesizeToFile
 */
public static int getMaxSpeechInputLength() {
    return 4000;
}

尽量不要超过该限制:将输入文本长度与该值进行比较,并在必要时拆分为单独的部分。

【讨论】:

  • 天哪。那么我怎样才能让应用程序说出我的话呢?有很多超过 4000 个字母!
  • 您需要将字符串拆分为句子或段落并分别发送(即,多次调用speak(),每次发送一个句子/一段文本)。例如,请参阅stackoverflow.com/questions/9675359/…,了解如何实现拆分。
  • @shoerat 如何让我的 10k + 角色必须使用 tts dude.what to do
  • @KarthickM 您的问题已在上述帖子和 cmets 中得到解答。如果您尝试了所有这些但仍然遇到问题,那么您的问题可能与文本限制无关。
  • 我有一个问题,如果所需的最小 SDK 为 18 并且我支持 14,我应该如何调用 getMaxSpeechInputLength ()?如果一个语音调用支持 API 4,那么 18 岁以下的设备无法处理这个限制,这没有任何意义?
【解决方案2】:

这比 Android 上的 4000 个字符限制更糟糕。有一些 TTS 引擎会更多地限制输入长度。例如 Nuance.tts 和 vocalizer.tts 引擎不会说出任何长度超过 512 个字符的字符串(来自我前段时间的测试)。今天我在 es.codefactory.eloquencetts 包中达到了低于 300 个字符的限制,如果我发送给它的字符串超过 256-300 个字符,它就会崩溃。我将内容分成句子,并注意超过上述限制的句子,在我的应用代码中进一步细分。

格雷格

【讨论】:

    【解决方案3】:

    如果你听从 ozbek 的建议,你应该没问题。我也有我想要说的大文本文件。我只是使用了流式阅读器方法,一切正常。这是我的代码的一部分。这是您应该使用的部分。我的代码比你想要的多一点,但它对我有用,也可能对你有用。

    Dim sReader As StreamReader = New StreamReader(Story_file) 试试

            Do Until EndOfStream '= True
                Dim line_to_speak As String = sReader.ReadLine
                Dim vc = Mid(line_to_speak, 1, 1) <- you dont need this
    
                Select Case vc  <- you dont need this
                    Case Is = "/" <- you dont need this
                        voice_index = Val(Mid(line_to_speak, 2, 2)) <- you dont need this
                        srate = Val(Mid(line_to_speak, 5, 2)) <- you dont need this
                        edassistv.lstVoices.SelectedIndex = voice_index <- you dont need this
                        selected_voice = edassistv.lstVoices.SelectedItem <- you dont need this
                    Case Else<- you dont need this
                        synth.SelectVoice(selected_voice)
                        synth.Speak(line_to_speak)
                End Select<- you dont need this
    
            Loop
        Catch ex As Exception
            GoTo finish
    

    【讨论】:

      【解决方案4】:

      使用此代码...适用于任何文件.. 只需将字符串发送到语音功能..

      private void speech(String charSequence) {
      
          int position ;
      
      
          int sizeOfChar= charSequence.length();
          String testStri= charSequence.substring(position,sizeOfChar);
      
      
          int next = 20;
          int pos =0;
          while(true) {
              String temp="";
              Log.e("in loop", "" + pos);
      
              try {
      
            temp = testStri.substring(pos, next);
                  HashMap<String, String> params = new HashMap<String, String>();
                  params.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, temp);
                  engine.speak(temp, TextToSpeech.QUEUE_ADD, params);
      
                  pos = pos + 20;
                  next = next + 20;
      
              } catch (Exception e) {
                  temp = testStri.substring(pos, testStri.length());
                  engine.speak(temp, TextToSpeech.QUEUE_ADD, null);
                  break;
      
              }
      
          }
      
      }
      

      【讨论】:

        【解决方案5】:

        以防有人觉得这很有帮助。将大文本拆分为字符串时,不要将每个字符串的长度设置为 getMaxSpeechInputLength() 的确切值。字符串长度减1。否则,TTS只能读取字符串的最后一块。

        int length = toSpeech.getMaxSpeechInputLength() - 1;
        Iterable<String> chunks = Splitter.fixedLength(length).split(largeText);
        Lists.newArrayList(chunks);
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-03-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多