Android Text-To-Speech API звучит роботизированно

Я впервые изучаю разработку для Android, и моя цель — создать простое приложение Hello World, которое принимает текст и читает его вслух.

Я основывал свой код на примере, который нашел, и вот мой код:

class MainFeeds : AppCompatActivity() {


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main_feeds)



        card.setOnClickListener{
            Toast.makeText(this, "Hello", Toast.LENGTH_LONG).show()
            TTS(this, "Hello this is leo")
        }
    }

}


class TTS(private val activity: Activity,
          private val message: String) : TextToSpeech.OnInitListener {

          private val tts: TextToSpeech = TextToSpeech(activity, this, "com.google.android.tts")

    override fun onInit(i: Int) {
        if (i == TextToSpeech.SUCCESS) {

            val localeUS = Locale.US

            val result: Int
            result = tts.setLanguage(localeUS)

            if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) {
                Toast.makeText(activity, "This Language is not supported", Toast.LENGTH_SHORT).show()
            } else {
                speakOut(message)
            }

        } else {
            Toast.makeText(activity, "Initilization Failed!", Toast.LENGTH_SHORT).show()
        }
    }

    private fun speakOut(message: String) {
        tts.speak(message, TextToSpeech.QUEUE_FLUSH, null, null)
    }
}

И это работает отлично, проблема, с которой я сталкиваюсь, заключается в том, что звук, исходящий от синтезатора, звучит очень роботизированно, почти как когда я использую Google Maps и отключаюсь от Интернета. Использует ли голосовой помощник Google какой-либо другой API, который мне нужно включить?

РЕДАКТИРОВАТЬ: я пытался запустить приложение на своем пикселе 2xl, и оно по-прежнему звучит как робот, так как оно не использует голос Google Assistant.


person Stupid.Fat.Cat    schedule 25.07.2018    source источник
comment
Вероятно, вы используете эмулятор, в котором не установлены API Google, и поэтому используется движок PICO. Устройство, которое вы тестируете, на том же устройстве, которое вы используете для Google Assistant?   -  person Nerdy Bunz    schedule 25.07.2018
comment
Ах нет, вы правы, я использую эмулятор, и я не пробовал Google Assistant на самом эмуляторе. Вы случайно не знаете, какой API мне нужно установить? Кажется, у меня 27 уровень.   -  person Stupid.Fat.Cat    schedule 25.07.2018
comment
вы пробовали тестовую программу?   -  person Nerdy Bunz    schedule 05.08.2018


Ответы (2)


Я сделал небольшую тестовую программу, которая должна ответить вам на этот вопрос.

Он показывает вам список всех голосов, которые есть в движке Google, и вы нажимаете на них и слушаете их! Ура!

Что он делает на самом деле:

  • Инициализирует объект TextToSpeech с помощью механизма преобразования текста в речь Google, если он существует на устройстве.
  • Позволяет выбрать конкретный голос из ListView, который содержит ВСЕ потенциально доступные голоса, соответствующие языковому стандарту, указанному в коде (в данном случае английскому)... и соответствующие версии установленного вами механизма преобразования текста в речь Google.

Таким образом, вы можете протестировать все голоса, чтобы увидеть, находится ли где-то там нужный вам голос «Google Ассистент», и если он недоступен, вы можете продолжать проверять по мере выпуска новых версий механизма преобразования текста в речь Google. Мне кажется, что самые качественные голоса в этом тесте имеют как качество:400, так и указание на то, что требуется подключение к сети.

ПРИМЕЧАНИЯ:

  • Голос (особенно английский) скорее всего все равно будет "играть", даже если он "не установлен". Это связано с тем, что при использовании setVoice(Voice v) движок (Google) вернет целое число "успех", даже если запрошенный голос недоступен (!), если у него есть какой-то другой "резервный" голос под рукой. того же языка. К сожалению, он делает все это в фоновом режиме и по-прежнему украдкой сообщает, что использует тот же самый голос, который вы запрашивали, даже если вы используете getVoice() и сравниваете объекты. :(.

  • Как правило, если голос говорит, что он установлен, то голос, который вы слышите, — это голос, который вы запрашивали.

  • По этим причинам вам нужно убедиться, что вы находитесь в Интернете, когда будете тестировать эти голоса (чтобы они автоматически устанавливались, когда вы запрашиваете недоступные голоса)... а также чтобы голоса, требующие сетевого подключения, не "автоматический даунгрейд".

  • Вы можете провести/обновить список голосов, чтобы проверить, были ли они уже установлены, или использовать раскрывающееся меню системы для просмотра загрузок... или перейти к настройкам преобразования текста в речь Google в системных настройках устройства. .

  • В представлении списка голосовые функции, такие как «требуется сеть» и «установлено», являются просто отголосками того, что сообщает механизм Google, и могут быть неточными. :(

  • Максимально возможное качество голоса, указанное в документации класса Voice, равно 500. . В своих тестах я смог найти только голоса с качеством до 400. Это может быть связано с тем, что на моем тестовом устройстве не установлена ​​последняя версия Google для преобразования текста в речь (и у меня нет доступа к Play Store на нем в порядок его обновления). Если вы используете реальное устройство, я предлагаю установить последнюю версию Google TTS с помощью Google Play Store. Проверить версию движка можно в журналах. Согласно Википедии, последняя версия на момент написания этой статьи — 3.15.18.200023596. Версия на моем тестовом устройстве — 3.13.1.

Чтобы воссоздать это тестовое приложение, создайте пустой проект Java в Android Studio с минимальным API 21. (getVoices() не работает до 21).

Манифест:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package=" [ your.package.name ] "
    android:windowSoftInputMode="stateHidden">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

Основная деятельность:

package [ your package name ];

import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.Color;
import android.speech.tts.TextToSpeech;
import android.speech.tts.UtteranceProgressListener;
import android.speech.tts.Voice;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Spinner;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;

public class MainActivity extends AppCompatActivity {

    EditText textToSpeak;
    TextView progressView;
    TextToSpeech googleTTS;
    ListView voiceListView;
    SwipeRefreshLayout swipeRefreshLayout;
    Long timeOfSpeakRequest;

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

        textToSpeak = findViewById(R.id.textToSpeak);
        textToSpeak.setText("Do I sound robotic to you?  1,2,3,4... yabadabadoo.  "
                + "ooo! ahh! la-la-la-la-la!  num-num-dibby-dibby-num-tick-tock...  "
                + "Can I pronounce the word, Antidisestablishmentarianism?  "
                + "Gerp!  My pants are too tight!  "
                + "CODE RED!  CODE RED!  Initiate disassemble!  Ice Cream is cold "
                + "...in my pants.  Exterminate!  exterminate!  Directive 4 is "
                + "classified."
        );
        progressView = findViewById(R.id.progressView);
        voiceListView = findViewById(R.id.voiceListView);
        swipeRefreshLayout = findViewById(R.id.swipeRefresh);


        // Create the TTS and wait until it's initialized to do anything else
        if (isGoogleEngineInstalled()) {
            createGoogleTTS();
        } else {
            Log.i("XXX", "onCreate(): Google not installed -- nothing done.");
        }

    }

    @Override
    protected void onStart() {
        super.onStart();

        swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                assignFullSetOfVoicesToVoiceListView();
            }
        });

    }

    // this is where the program really begins (when the TTS is initialized)
    private void onTTSInitialized() {

        setUpWhatHappensWhenAVoiceItemIsClicked();
        setUtteranceProgressListenerOnTheTTS();
        assignFullSetOfVoicesToVoiceListView();

    }

    // FACTORED/EXTRACTED METHODS ----------------------------------------------------------------
    // These are just pulled out to make onCreate() easier to read and the basic sequence
    // of events more obvious.

    private void createGoogleTTS() {

        googleTTS = new TextToSpeech(this, new TextToSpeech.OnInitListener() {
            @Override
            public void onInit(int status) {
                if (status != TextToSpeech.ERROR) {
                    Log.i("XXX", "Google tts initialized");
                    onTTSInitialized();
                } else {
                    Log.i("XXX", "Internal Google engine init error.");
                }
            }
        }, "com.google.android.tts");

    }

    private void setUpWhatHappensWhenAVoiceItemIsClicked() {
        voiceListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Voice desiredVoice = (Voice) parent.getAdapter().getItem(position);
                // if (setting the desired voice is "successful")...
                // in the case of google engine, this does not necessarily mean the voice you
                // want will actually be used. :(
                if (googleTTS.setVoice(desiredVoice) == 0) {
                    Log.i("XXX", "Speech voice set to: " + desiredVoice.toString());
                    // TTS did may "auto-downgrade" voice selection
                    // due to internal reason such as no data
                    // Unfortunately it will not tell you, and there seems to be no
                    // way of checking whether the presently selected voice (getVoice()) "equals"
                    // the desired voice.
                    speak();
                }
            }
        });
    }

    private void setUtteranceProgressListenerOnTheTTS() {

        UtteranceProgressListener blurp = new UtteranceProgressListener() {

            @Override // MIN API 15
            public void onStart(String s) {
                long timeSinceSpeakCall = System.currentTimeMillis() - timeOfSpeakRequest;
                Log.i("XXX", "progress.onStart() callback.  "
                        + timeSinceSpeakCall + " millis since speak() was called.");
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        progressView.setTextColor(Color.GREEN);
                        progressView.setText("PROGRESS: STARTED");
                    }
                });
            }

            @Override // MIN API 15
            public void onDone(String s) {
                long timeSinceSpeakCall = System.currentTimeMillis() - timeOfSpeakRequest;
                Log.i("XXX", "progress.onDone() callback.  "
                        + timeSinceSpeakCall + " millis since speak() was called.");
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        progressView.setTextColor(Color.GREEN);
                        progressView.setText("PROGRESS: DONE");
                    }
                });
            }

            // Getting an error can simply mean that the particular voice is not available
            // to the device yet... and still needs to be downloaded / is still downloading
            @Override // MIN API 15 (depracated at API 21)
            public void onError(String s) {
                long timeSinceSpeakCall = System.currentTimeMillis() - timeOfSpeakRequest;
                Log.i("XXX", "progress.onERROR() callback.  "
                        + timeSinceSpeakCall + " millis since speak() was called.");
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        progressView.setTextColor(Color.RED);
                        progressView.setText("PROGRESS: ERROR");
                    }
                });

            }
        };
        googleTTS.setOnUtteranceProgressListener(blurp);

    }

    // must happens AFTER tts is initialized
    private void assignFullSetOfVoicesToVoiceListView() {

        googleTTS.stop();

        List<Voice> tempVoiceList = new ArrayList<>();

        for (Voice v : googleTTS.getVoices()) {
            if (v.getLocale().getLanguage().contains("en")) { // only English voices
                tempVoiceList.add(v);
            }
        }

        // Sort the list alphabetically by name
        Collections.sort(tempVoiceList, new Comparator<Voice>() {
            @Override
            public int compare(Voice v1, Voice v2) {
                Log.i("XXX", "comparing item");
                return (v2.getName().compareToIgnoreCase(v1.getName()));
            }
        });

        VoiceAdapter tempAdapter = new VoiceAdapter(this, tempVoiceList);

        voiceListView.setAdapter(tempAdapter);
        swipeRefreshLayout.setRefreshing(false);
        progressView.setTextColor(Color.BLACK);
        progressView.setText("PROGRESS: ...");

    }

    private void speak() {
        HashMap<String, String> map = new HashMap<>();
        map.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "merp");
        timeOfSpeakRequest = System.currentTimeMillis();
        googleTTS.speak(textToSpeak.getText().toString(), TextToSpeech.QUEUE_FLUSH, map);
    }

    // Checks if Google Engine is installed
    // ... (and gives more info in Logs).
    // The version number is going to dictate the quality of voices available
    private boolean isGoogleEngineInstalled() {

        final Intent ttsIntent = new Intent();
        ttsIntent.setAction(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA);
        final PackageManager pm = getPackageManager();
        final List<ResolveInfo> list = pm.queryIntentActivities(ttsIntent, PackageManager.GET_META_DATA);

        boolean googleIsInstalled = false;

        for (int i = 0; i < list.size(); i++) {

            ResolveInfo resolveInfoUnderScrutiny = list.get(i);
            String engineName = resolveInfoUnderScrutiny.activityInfo.applicationInfo.packageName;

            if (engineName.equals("com.google.android.tts")) {
                String version = "null";
                try {
                    version = pm.getPackageInfo(engineName,
                            PackageManager.GET_META_DATA).versionName;
                } catch (Exception e) {
                    Log.i("XXX", "Error getting google engine verion: " + e.toString());
                }
                Log.i("XXX", "Google engine version " + version + " is installed!");
                googleIsInstalled = true;
            } else {
                Log.i("XXX", "Google Engine is not installed!");
            }

        }
        return googleIsInstalled;
    }
}

VoiceAdapter.java:

package [ your package name ];

import android.content.Context;
import android.graphics.Color;
import android.speech.tts.Voice;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

import java.util.List;

public class VoiceAdapter extends BaseAdapter {

    private Context mContext;
    private LayoutInflater mInflater;
    private List<Voice> mDataSource;

    public VoiceAdapter(Context context, List<Voice> voicesToDisplay) {
        mContext = context;
        mDataSource = voicesToDisplay;
        mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

    @Override
    public int getCount() {
        return mDataSource.size();
    }

    @Override
    public Object getItem(int position) {
        return mDataSource.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        // In a real app this method is not efficient,
        // and "View Holder Pattern" shoudl be used instead.
        View rowView = mInflater.inflate(R.layout.list_item_voice, parent, false);

        if (position%2 == 0) {
            rowView.setBackgroundColor(Color.rgb(245,245,245));
        }

        Voice voiceUnderScrutiny = mDataSource.get(position);

        // example output of Voice.toString() :
        // "Voice[Name: pt-br-x-afs#male_2-local, locale: pt_BR, quality: 400, latency: 200,
        // requiresNetwork: false, features: [networkTimeoutMs, notInstalled, networkRetriesCount]]"

        // Get title element
        TextView voiceTitleTextView =
                (TextView) rowView.findViewById(R.id.voice_title);

        TextView qualityTextView =
                (TextView) rowView.findViewById(R.id.voice_quality);

        TextView networkRequiredTextView =
                (TextView) rowView.findViewById(R.id.voice_network);

        TextView isInstalledTextView =
                (TextView) rowView.findViewById(R.id.voice_installed);

        TextView featuresTextView =
                (TextView) rowView.findViewById(R.id.voice_features);

        voiceTitleTextView.setText("VOICE NAME: " + voiceUnderScrutiny.getName());

        // Voice Quality...
        // ( https://developer.android.com/reference/android/speech/tts/Voice.html )
        // 100 = Very Low, 200 = Low, 300 = Normal, 400 = High, 500 = Very High
        qualityTextView.setText(  "QLTY: " + ((Integer) voiceUnderScrutiny.getQuality()).toString()  );
        if (voiceUnderScrutiny.getQuality() == 500) {
            qualityTextView.setTextColor(Color.GREEN); // set v. high quality to green
        }

        if (!voiceUnderScrutiny.isNetworkConnectionRequired()) {
            networkRequiredTextView.setText("NET_REQ?: NO");
        } else {
            networkRequiredTextView.setText("NET_REQ?: YES");
        }

        if (!voiceUnderScrutiny.getFeatures().contains("notInstalled")) {
            isInstalledTextView.setTextColor(Color.GREEN);
            isInstalledTextView.setText("INSTLLD?: YES");
        } else {
            isInstalledTextView.setTextColor(Color.RED);
            isInstalledTextView.setText("INSTLLD?: NO");
        }

        featuresTextView.setText("FEATURES: " + voiceUnderScrutiny.getFeatures().toString());

        return rowView;
    }
}

Activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:focusable="true"
    android:focusableInTouchMode="true"
    tools:context=".MainActivity">

    <EditText
        android:id="@+id/textToSpeak"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginEnd="8dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:ems="10"
        android:inputType="textPersonName"
        android:text="textToSpeak..."
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <android.support.v4.widget.SwipeRefreshLayout
        android:id="@+id/swipeRefresh"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginBottom="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/progressView">

    <ListView
        android:id="@+id/voiceListView"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginBottom="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp">

    </ListView>

    </android.support.v4.widget.SwipeRefreshLayout>

    <TextView
        android:id="@+id/progressView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="8dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:text="UTTERANCE_PROGRESS:"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textToSpeak" />

</android.support.constraint.ConstraintLayout>

list_item_voice.xml:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"

    android:layout_centerInParent="true"
    android:paddingBottom="8dp"
    android:paddingLeft="16dp"
    android:paddingRight="16dp"
    android:paddingTop="8dp"
    >

    <TextView
        android:id="@+id/voice_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="8dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:text="NAME:"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />


    <TextView
        android:id="@+id/voice_installed"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:fontFamily="monospace"
        android:text="INSTALLED? "
        android:textAlignment="textStart"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toEndOf="@+id/voice_network"
        app:layout_constraintTop_toBottomOf="@+id/voice_title" />

    <TextView
        android:id="@+id/voice_quality"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="8dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:text="QUALITY:"
        app:layout_constraintEnd_toStartOf="@+id/voice_network"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/voice_title" />

    <TextView
        android:id="@+id/voice_features"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:text="FEATURES:"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/voice_quality" />

    <TextView
        android:id="@+id/voice_network"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="8dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:text="NET_REQUIRED?"
        app:layout_constraintEnd_toStartOf="@+id/voice_installed"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toEndOf="@+id/voice_quality"
        app:layout_constraintTop_toBottomOf="@+id/voice_title" />

</android.support.constraint.ConstraintLayout>
person Nerdy Bunz    schedule 31.07.2018
comment
Проверено, работает как шарм. Также есть качество 400 на максимуме, хотя этого более чем достаточно, очень нравится. Кстати, блестящий образец текста :) - person Oleg Talaver; 31.03.2021

Качество речи в первую очередь зависит от того, какой «речевой движок» используется созданным вами объектом TextToSpeech:

private val tts: TextToSpeech = TextToSpeech(activity, this)

Если бы вместо этого вы ввели:

private val tts: TextToSpeech = TextToSpeech(activity, this, "com.google.android.tts")

...тогда любое устройство, на котором вы запускаете этот код, будет попытаться использовать речевой движок Google... но на самом деле он будет использоваться только в том случае, если он существует на устройстве.

Точно так же при использовании «com.samsung.SMT» будет предпринята попытка использовать речевой движок Samsung (который также является высококачественным, но обычно устанавливается только на [реальных] устройствах Samsung).

Будет ли доступен речевой движок Google, зависит не столько от уровня Android API устройства (при условии, что он достаточно новый для запуска движка Google), сколько от фактического движка Google для преобразования текста в речь. установлен на устройстве вообще.

Чтобы убедиться, что движок Google установлен:

В эмуляторе Android Studio:

Создайте новый эмулятор и выберите системный образ с «API Google» или «Google Play» в столбце «Цель».

На реальном устройстве:

Перейдите в Play Маркет и установите речевой движок Google. .

TTS на Android (или, по крайней мере, попытка предсказать его поведение) может быть настоящим зверем.

Документация: Java | Котлин.

person Nerdy Bunz    schedule 25.07.2018
comment
Спасибо за ответ, Бубер, я попытался создать новый эмулятор с изображением, у которого есть Google API в целевом столбце, но он все еще использует этот роботизированный голос даже после изменения кода. Это странно. - person Stupid.Fat.Cat; 26.07.2018
comment
Я также пробовал это на своем пикселе 2xl, и это все еще звучит как робот. - person Stupid.Fat.Cat; 26.07.2018
comment
Ну, я полагаю, что робототехника субъективна. Вы имеете в виду Стивена Хокинга? ... или просто узнаваемо нечеловеческий. В любом случае... в документации вы можете узнать, как выбирать отдельные голоса... некоторые из них используют ИИ и основаны на облаке... вероятно, это те, которые вы ищете... но я предполагаю, что он будет автоматически выбирать голос лучшего качества по умолчанию. Что ж, тем больше причин для диагностического приложения. - person Nerdy Bunz; 26.07.2018
comment
Под роботизированным я подразумеваю, что это не тот же голос, что и у Google Assistant. Я буду продолжать играть с ним. - person Stupid.Fat.Cat; 26.07.2018