简体   繁体   English

Android TTS 无法朗读大量文本

[英]Android TTS fails to speak large amount of text

I am trying to speak out large amount of text using Android Text To Speech.我正在尝试使用 Android Text To Speech 说出大量文本。 I using default Google speech engine.我使用默认的谷歌语音引擎。 Below is my code.下面是我的代码。

 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();
            }

    }

But the issue here is, when there is a large chunk of text (lets say you have extracted text from a web page) the TTS fails to read it.但这里的问题是,当有大量文本时(假设您从网页中提取了文本),TTS 无法读取。 If I remove most of the text, then it will read it.如果我删除大部分文本,那么它会阅读它。 Why is this happening?为什么会这样?

When I am about to read the large text, the LogCat however display something like this当我要阅读大文本时,LogCat 会显示类似这样的内容

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

The String length should not be longer than pre-defined length, from docs :字符串长度不应超过预定义的长度,来自docs

Parameters参数

text The string of text to be spoken. text要朗读的文本字符串。 No longer than getMaxSpeechInputLength() characters.不超过getMaxSpeechInputLength()字符。

Returned value by getMaxSpeechInputLength() may vary from device to device, but according to AOSP source that is whopping 4000 : getMaxSpeechInputLength()返回值可能因设备而异,但根据AOSP 来源高达4000

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

Try not to exceed that limit: compare input text length with that value and split into separate parts if necessary.尽量不要超过该限制:将输入文本长度与该值进行比较,并在必要时拆分为单独的部分。

Use this code...Working for any file .. just send the string to speech function..使用此代码......适用于任何文件......只需将字符串发送到语音功能......

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;

        }

    }

}

It is worse than the 4000 characters limit in practice on Android.它比 Android 上的 4000 个字符限制更糟糕。 There are some TTS engines that limit the input length a lot more.有一些 TTS 引擎会更多地限制输入长度。 For example Nuance.tts and vocalizer.tts engines won't speak any string longer than about 512 characters (from my tests some time ago).例如,Nuance.tts 和vocalizer.tts 引擎不会说出任何超过512 个字符的字符串(来自我前一段时间的测试)。 Today I hit a limit of below 300 characters in es.codefactory.eloquencetts package, which simply crashes if the string I send to it is more than 256-300 characters.今天我在 es.codefactory.eloquencetts 包中达到了低于 300 个字符的限制,如果我发送给它的字符串超过 256-300 个字符,它就会崩溃。 I divide the contents into sentences, and guard for sentences longer than the above limit, further sub-dividing them in my app code.我将内容分成句子,并保护超过上述限制的句子,并在我的应用程序代码中进一步细分。

Greg格雷格

If you follow ozbek's advice you should be fine.如果您遵循 ozbek 的建议,您应该没问题。 I too have large text files that I want spoken.我也有我想说的大文本文件。 I simply used the streamreader method and everything works fine.我只是使用了 streamreader 方法,一切正常。 heres' PART of my code.这是我的代码的一部分。 it's the part that you should use.这是你应该使用的部分。 My code does a bit more than you want but it works for me and may work for you.我的代码做的比你想要的多一点,但它对我有用,也可能对你有用。

Dim sReader As StreamReader = New StreamReader(Story_file) Try 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

In case someone might find this helpful.如果有人可能会发现这有帮助。 When you split the large text into strings, do not set the length of each string to the exact value of getMaxSpeechInputLength() .将大文本拆分为字符串时,不要将每个字符串的长度设置为getMaxSpeechInputLength()的确切值。 Subtract the string length by 1. Otherwise, only the last chunk of string could be read by TTS.将字符串长度减 1。否则,TTS 只能读取字符串的最后一个块。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM