【安卓学习之开源项目】 ParrotTongue:文字转语音(含LeLeTextToVoice、TextToMp3项目)

█ 【安卓学习之开源项目】 ParrotTongue:文字转语音(含LeLeTextToVoice、TextToMp3项目)


█ 系列文章目录

提示:这里是收集了和音频有关的文章


█ 文章目录


█ 读前说明

  • 本文通过学习别人写demo,学习一些课件,参考一些博客,’学习相关知识,如果涉及侵权请告知
  • 本文只简单罗列相关的代码实现过程
  • 涉及到的逻辑以及说明也只是简单介绍,主要当做笔记,了解过程而已
  • 项目源码:ParrotTongue
  • demo:ParrotTongue文字转语音20210814.zip

█ 项目UI

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

█ 项目信息

⚡️ 提交信息:2020 年 2 月 7 日
在这里插入图片描述

⚡️ 配置信息
 ● 在Project的build.gradle文件中配置:

buildscript {
    repositories {
        google()
        jcenter()  
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.5.2'// 升级为 4.1.1
    }
}

● 在Project的gradle-wrapper.properties文件中配置:

#Sun Dec 08 22:42:32 CST 2019
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip// 升级为 6.5

● 在Module的build.gradle文件中添加依赖和属性配置:

android {
    compileSdkVersion 29
    buildToolsVersion "29.0.2"
    defaultConfig {
        applicationId "com.whn946.parrottongue"
        minSdkVersion 21
        targetSdkVersion 29
        versionCode 4
        versionName "2.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }
}

█ 核心代码:TextToSpeech

⚡️ 相关方法

public String getDefaultEngine()获取默认引擎
public Locale getDefaultLanguage()获取默认引擎语言
public String getCurrentEngine()获取当前引擎(改方法不可见)
public Locale getLanguage()获取当前引擎语言

⚡️ AudioUtil :读取列表、初始化
封装系统TTS列表数据

小米手机语言与输入法→文字转语音(TTS)输出→首选引擎→ 小爱语音引擎tts.getDefaultEngine()com.xiaomi.mibrain.speech
工控设备语言与输入法→文字转语音(TTS)输出→首选引擎→ Pico TTStts.getDefaultEngine()com.svox.pico
xxx语音引擎停用tts.getDefaultEngine()
tts.getEngines()
null
size() = 0

实例化(注意以下)

引擎statusonInit(int status)
执行时间
tts.getEngines()
执行时间
执行顺序
正常SUCCESS = 0560ms
tts不为null
67ms
tts不为null
先执行tts.getEngines(),再执行onInit(int status)
onInit(int status)中,可以正常引用tts,tts已创建成功
被停用ERROR = -155ms
tts为null
56ms
tts不为null
先执行onInit(int status),再执行tts.getEngines()
onInit(int status)中,如果引用tts,未赋值,会报NullPointer异常
public static List<TextToSpeech.EngineInfo> getTtsList(Context context) {
	// Google 文字转语音引擎: 语言分为 英语(美国) eng_USA、中文(中国) zho_CHN、中文(台湾) zho_TWN
	// 以下 xxx 表示当前系统设置的语音引擎的语言
    TextToSpeech  tts = new TextToSpeech(context, new TextToSpeech.OnInitListener() {
        @Override
        public void onInit(int status) {// 大约需要60ms-500ms
        	// 初始化成功后,默认引擎:com.google.android.tts,语言:xxx (如zho_CHN),默认语言:xxx (如zho_CHN)
        	int supported = mTextToSpeech.setLanguage(Locale.CHINA);// 设置 zh_CN
        	// supported :1,即LANG_COUNTRY_AVAILABLE,说明 语言的国家存在,地区不存在
        	// 修改语言后,默认引擎:com.google.android.tts,语言:zho_CHN,默认语言:xxx (如zho_CHN)
        	// 修改语言后,默认引擎:com.iflytek.speechcloud,语言:zho,默认语言:xxx (如zho_CHN)
        	int supported = mTextToSpeech.setLanguage(Locale.US);// 设置 en_US
        	// supported :1,即LANG_COUNTRY_AVAILABLE,说明 语言的国家存在,地区不存在
        	// 修改语言后,默认引擎:com.google.android.tts,语言:eng_USA,默认语言:xxx (如zho_CHN)
        	// 修改语言后,默认引擎:com.iflytek.speechcloud,语言:eng,默认语言:xxx (如zho_CHN)
        }
    });
    // 此时新建(初始化中...),默认引擎:com.google.android.tts,语言:null,默认引擎语言:null
    List<TextToSpeech.EngineInfo> list = tts.getEngines();
    // [{"icon":0,"label":"Pico TTS","name":"com.svox.pico","priority":0,"system":true},
    // {"icon":2130837536,"label":"Google文字转语音引擎","name":"com.google.android.tts","priority":100,"system":false},
    // {"icon":2130837504,"label":"度秘语音引擎3.0","name":"com.baidu.duersdk.opensdk","priority":0,"system":false},
    // {"icon":2130837527,"label":"科大讯飞语音引擎3.0","name":"com.iflytek.speechcloud","priority":0,"system":false},
    // {"icon":2130837504,"label":"讯飞语音合成","name":"com.iflytek.tts","priority":0,"system":false},
    // {"icon":2131558400,"label":"系统语音引擎","name":"com.xiaomi.mibrain.speech","priority":0,"system":false}]
    // {"icon":2131558400,"label":"Google 文字转语音引擎","name":"com.google.android.tts","priority":100,"system":true}
    // {"icon":2130903040,"label":"小爱语音引擎","name":"com.xiaomi.mibrain.speech","priority":0,"system":false}
    System.out.println(list);
    return tts.getEngines();
}

初始化TTS服务:设置引擎(讯飞语音引擎、小爱语音引擎等)、设置语言

小米手机语言与输入法→文字转语音(TTS)输出→首选引擎→ 小爱语音引擎tts2.getDefaultEngine()com.xiaomi.mibrain.speech
工控设备语言与输入法→文字转语音(TTS)输出→首选引擎→ Pico TTStts2.getDefaultEngine()com.svox.pico
xxx语音引擎停用tts2.getDefaultEngine()
tts2.getEngines()
null
size() = 0
public static TextToSpeech initTTS(final Context context, final String engine) {
    final TextToSpeech tts2= new TextToSpeech(context, new TextToSpeech.OnInitListener() {
        @Override
        public void onInit(int status) {// 大约需要60ms
            int supported = 0;
            if (status == TextToSpeech.SUCCESS) {
                SharedPreferences tts_lan = context.getSharedPreferences("tts_lan", Context.MODE_PRIVATE);
                String lan_str = tts_lan.getString("tts_lan", "");// lan_str = CHINA
                //设置朗读语言
                if (lan_str.equals("CHINA")) {
                    supported = mTextToSpeech.setLanguage(Locale.CHINA);
                } else if (lan_str.equals("US")) {
                    supported = mTextToSpeech.setLanguage(Locale.US);
                }
                if ((supported != TextToSpeech.LANG_AVAILABLE) 
                	&& (supported != TextToSpeech.LANG_COUNTRY_AVAILABLE)) {
                    Toast.makeText(context, "不支持当前语言!", Toast.LENGTH_SHORT).show();
                }
            }
        }
    }, engine);// engine = com.xiaomi.mibrain.speech(按拼音排序,默认为小爱)
	// tts2.setPitch(pitchNum);// 语调设置
	// tts2.setSpeechRate(speechRateNum);// 语速设置
    return tts2;
}

█ 核心代码:DefaultModeActivity

⚡️ 初始化引擎 getTtsListData()

 private TextToSpeech tts22;
public void getTtsListData() {
    //获取原始列表
    List<TextToSpeech.EngineInfo> tts_list = AudioUtil.getTtsList(mc);
    。。。。。。// 按拼音排序引擎,存入 tts_map
    tts22 = AudioUtil.initTTS(this, tts_map.get(0);// 默认取第一个 小爱语音引擎
    tts22.setOnUtteranceProgressListener(new UtteranceProgressListener() {
        @Override
        public void onStart(String utteranceId) {
            // 朗读中...
        }

        @Override
        public void onDone(String utteranceId) {
            tts22.stop();
            // 循环朗读 处理
            if (isLoop && loopNum > 1) {
                String str = et.getText().toString();
                if (!tts22.isSpeaking()) {
                    tts22.speak(str, TextToSpeech.QUEUE_ADD, null, getString(R.string.app_name));
                }
                loopNum--;
            } else {
                tts22.stop();
            }
        }

        @Override
        public void onError(String utteranceId) {
        }

        @Override
        public void onError(String utteranceId, int errorCode) {
        }
    });
}

⚡️ 修改语音引擎

Spinner.setOnItemSelectedListener(new Spinner.OnItemSelectedListener() {
    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
        tts22.setEngineByPackageName(tts_map.get(ttsListSp.getSelectedItem().toString()).toString());
    }

    @Override
    public void onNothingSelected(AdapterView<?> parent) {

    }
});

⚡️ 开始朗读和停止朗读

//开始朗读
speakBtn.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View arg0) {
        tts22.setPitch(pitchNum);
        tts22.setSpeechRate(speechRateNum);
        String str = et.getText().toString();
        if (str.trim().equals("")) {
            sysToolUtil.msgAlert("提示", "朗读内容不能为空!", "好的", mc);
        } else {
            tts22.speak(str, TextToSpeech.QUEUE_FLUSH, null, getString(R.string.app_name));
        }
    }
});
//停止朗读
stopBtn.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View arg0) {
        if (tts22.isSpeaking()) {
            tts22.stop();
        }
    }
});

⚡️ 保存为MP3文件(需要权限申请)

//保存音频
saveBtn.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View arg0) {
        //按下确定键后的事件
        。。。。。。// 文件名为 fileName:xxx.mp3
        HashMap<String, String> myHashRender = new HashMap<String, String>();
        myHashRender.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, et.getText().toString());// 不能为空
        int r = tts22.synthesizeToFile(et.getText().toString(),myHashRender, fileName);
        // 弹框显示保存结果
        if (r == TextToSpeech.SUCCESS) {
            // 将请求添加到TTS的队列中,合成可能还没有完成
            // setOnUtteranceProgressListener 设置监听查看是否完成转换
            sysToolUtil.msgAlert("保存成功", "文件路径:sdcard/文转音/" + fileName, "OK", mc);
        } else {
            sysToolUtil.msgAlert("保存失败", "输出流异常!", "是", mc);
        }
    }
});

█ 常见问题

⚡️ 安装语音引擎
小米手机,默认已经安装了【小爱语音引擎】

tts = new TextToSpeech(context, OnInitListener);
List<TextToSpeech.EngineInfo> list = tts.getEngines();
System.out.println(list);
[{“icon”:2130837527,“label”:“科大讯飞语音引擎3.0”,“name”:“com.iflytek.speechcloud”},
{“icon”:2130903040,“label”:“小爱语音引擎”,“name”:“com.xiaomi.mibrain.speech”}]
引擎应用名应用包名说明
Pico TTSPico TTScom.svox.pico国内Android系统自带语音引擎包,不支持中文,支持美国英语、英语英语、法语、意大利语、德文、西班牙语
svoxsvox classic ttscom.svox.classic不支持中文语音
谷歌文字转语音引擎Google 文字转语音引擎 (V 3.9.11)
Google 文字转语音引擎 (V 24.9.361717975)
com.google.android.tts不支持5.0以下系统,大小17.98M,支持中文,支持30种语言
科大讯飞语音合成讯飞语音合成com.iflytek.tts较老,不支持7.0以上系统(会奔溃),大小9M
科大讯飞语音引擎3.0语音设置com.iflytek.speechcloud支持4.0以上系统,大小27.27M,支持粤语、东北话、河南话、湖南话、四川话、台湾话等
新版科大讯飞语音引擎com.iflytek.speechsuite2018年开始新版手机一般会内置,如oppo、vivo、华为
度秘语音引擎3.0语音识别设置com.baidu.duersdk.opensdk不支持5.0以下系统,大小11.95M
小爱语音引擎系统语音引擎(V 1.2.8)
小爱语音引擎(V 1.1.5)
com.xiaomi.mibrain.speech小米手机一般会内置,导出来的apk(V 1.1.5)会出现异常

在这里插入图片描述

在这里插入图片描述

⚡️ 雷电模拟器 4.0.44,系统自带【谷歌文字转语音引擎】24.5.347911411
在这里插入图片描述

⚡️将tts 语音引擎 停用,实例化一个TextToSpeech可能会为null,可以检查设备是否具有TTS功能​​

        Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
        intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, "en-US");
        try {
            startActivityForResult(intent, 1000);
            overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
        } catch (ActivityNotFoundException e) {
            Log.e("onTTSOnInit TTS",e.getMessage());
        }
D/SubSettings: Launching fragment com.android.settings.tts.TextToSpeechSettings
W/ContextImpl: Calling a method in the system process without a qualified user: android.app.ContextImpl.bindService:1556 android.content.ContextWrapper.bindService:684 android.speech.tts.TextToSpeech.connectToEngine:810 android.speech.tts.TextToSpeech.initTts:780 android.speech.tts.TextToSpeech.<init>:733 
I/ActivityManager: START u0 {act=android.speech.tts.engine.CHECK_TTS_DATA pkg=com.svox.pico cmp=com.svox.pico/.CheckVoiceData} from uid 1000
V/SynthProxy: About to load libttspico.so, applyFilter=true
D/onTTSOnInit TTS: No Activity found to handle Intent { act=android.speech.action.RECOGNIZE_SPEECH (has extras) }

⚡️【科大讯飞语音合成】 在android 7.0设备上 设置会奔溃

2021-08-20 09:51:44.036 4778-4778/? E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.iflytek.tts, PID: 4778
    java.lang.UnsatisfiedLinkError: dlopen failed: cannot locate symbol "BIO_f_cipher" referenced by "/data/app/com.iflytek.tts-9weCz673fGZfpxAffItn3A==/lib/arm/libwrapper.so"...
        at java.lang.Runtime.loadLibrary0(Runtime.java:1016)
        at java.lang.System.loadLibrary(System.java:1657)
        at com.iflytek.tts.SynthProxy.<clinit>(Unknown Source:7)
        at com.iflytek.tts.TtsService.onCreate(Unknown Source:75)
        at android.app.ActivityThread.handleCreateService(ActivityThread.java:3342)
        at android.app.ActivityThread.-wrap4(Unknown Source:0)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1680)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:164)
        at android.app.ActivityThread.main(ActivityThread.java:6518)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)

⚡️【小爱语音引擎(V 1.1.5)】 使用会奔溃奔溃,应该是缺少小米服务框架,就和【小米天气/MIUI天气】(com.miui.weather2)一样,可以安装,却无法打开
com.xiaomi.mibrain.speech 设置默认引擎时

2021-08-21 16:31:42.008 15516-15516/com.xiaomi.mibrain.speech E/com.xiaomi.ai.b.m: Construction failure. Failed to create folder /storage/emulated/0/MIUI/debug_log/com.xiaomi.mibrain.speech. 
2021-08-21 16:31:42.013 15516-15516/com.xiaomi.mibrain.speech E/MiSpeechSDK:VoiceRecognizeUtils: SocketException
    java.lang.SecurityException: getDeviceId: Neither user 10083 nor current process has android.permission.READ_PHONE_STATE.
        at android.os.Parcel.readException(Parcel.java:1684)
        at android.os.Parcel.readException(Parcel.java:1637)
        at com.android.internal.telephony.ITelephony$Stub$Proxy.getDeviceId(ITelephony.java:4454)
        at android.telephony.TelephonyManager.getDeviceId(TelephonyManager.java:861)
        at com.xiaomi.ai.b.o.b(Unknown Source)
        at com.xiaomi.ai.b.o.a(Unknown Source)
        at com.xiaomi.ai.ak.a(Unknown Source)
        at com.xiaomi.ai.ak.<init>(Unknown Source)
        at com.xiaomi.ai.ae.init(Unknown Source)
        at com.xiaomi.ai.n.createEngine(Unknown Source)
        at com.xiaomi.mibrain.speech.SpeechEngineApplication.onCreate(Unknown Source)
        at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1024)
        at android.app.ActivityThread.handleBindApplication(ActivityThread.java:5429)
        at android.app.ActivityThread.-wrap2(ActivityThread.java)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1550)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:154)
        at android.app.ActivityThread.main(ActivityThread.java:6145)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:892)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:782)
2021-08-21 16:31:42.144 1627-1627/com.android.settings E/TextToSpeechSettings: Failed to get sample text, no activity found for Intent { act=android.speech.tts.engine.GET_SAMPLE_TEXT pkg=com.xiaomi.mibrain.speech (has extras) })

com.xiaomi.mibrain.speech 调用播放接口

2021-08-21 16:36:37.957 19000-19000/com.xiaomi.mibrain.speech E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.xiaomi.mibrain.speech, PID: 19000
    java.lang.NoClassDefFoundError: Failed resolution of: Lmiui/app/AlertDialog$Builder;
        at com.xiaomi.mibrain.speech.CTAActivity.onCreate(Unknown Source)
        at android.app.Activity.performCreate(Activity.java:6698)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2623)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2731)
        at android.app.ActivityThread.-wrap12(ActivityThread.java)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1482)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:154)
        at android.app.ActivityThread.main(ActivityThread.java:6145)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:892)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:782)
     Caused by: java.lang.ClassNotFoundException: Didn't find class "miui.app.AlertDialog$Builder" on path: DexPathList[[zip file "/data/app/com.xiaomi.mibrain.speech-2/base.apk"],nativeLibraryDirectories=[/data/app/com.xiaomi.mibrain.speech-2/lib/arm, /data/app/com.xiaomi.mibrain.speech-2/base.apk!/lib/armeabi-v7a, /system/lib, /vendor/lib]]
        at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:380)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
        at com.xiaomi.mibrain.speech.CTAActivity.onCreate(Unknown Source) 
        at android.app.Activity.performCreate(Activity.java:6698) 
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118) 
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2623) 
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2731) 
        at android.app.ActivityThread.-wrap12(ActivityThread.java) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1482) 
        at android.os.Handler.dispatchMessage(Handler.java:102) 
        at android.os.Looper.loop(Looper.java:154) 
        at android.app.ActivityThread.main(ActivityThread.java:6145) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:892) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:782) 

com.miui.weather2 启动 MIUI天气 v12.5.9.0

021-08-21 16:23:09.487 5088-5088/com.miui.weather2 E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.miui.weather2, PID: 5088
    java.lang.NoClassDefFoundError: Failed resolution of: Lmiui/os/Build;
        at com.miui.weather2.tools.ia.c(SourceFile:1)
        at com.miui.weather2.WeatherApplication.onCreate(SourceFile:2)
        at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1024)
        at android.app.ActivityThread.handleBindApplication(ActivityThread.java:5429)
        at android.app.ActivityThread.-wrap2(ActivityThread.java)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1550)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:154)
        at android.app.ActivityThread.main(ActivityThread.java:6145)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:892)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:782)
     Caused by: java.lang.ClassNotFoundException: Didn't find class "miui.os.Build" on path: DexPathList[[zip file "/data/app/com.miui.weather2-1/base.apk"],nativeLibraryDirectories=[/data/app/com.miui.weather2-1/lib/arm, /data/app/com.miui.weather2-1/base.apk!/lib/armeabi, /system/lib, /vendor/lib]]
        at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:380)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
        at com.miui.weather2.tools.ia.c(SourceFile:1) 
        at com.miui.weather2.WeatherApplication.onCreate(SourceFile:2) 
        at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1024) 
        at android.app.ActivityThread.handleBindApplication(ActivityThread.java:5429) 
        at android.app.ActivityThread.-wrap2(ActivityThread.java) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1550) 
        at android.os.Handler.dispatchMessage(Handler.java:102) 
        at android.os.Looper.loop(Looper.java:154) 
        at android.app.ActivityThread.main(ActivityThread.java:6145) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:892) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:782) 

com.miui.weather2 启动 MIUI天气 v4.0.2

021-08-21 16:23:09.487 5088-5088/com.miui.weather2 E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.miui.weather2, PID: 5088
    java.lang.NoClassDefFoundError: Failed resolution of: Lmiui/os/Build;
        at com.miui.weather2.tools.ia.c(SourceFile:1)
        at com.miui.weather2.WeatherApplication.onCreate(SourceFile:2)
        at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1024)
        at android.app.ActivityThread.handleBindApplication(ActivityThread.java:5429)
        at android.app.ActivityThread.-wrap2(ActivityThread.java)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1550)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:154)
        at android.app.ActivityThread.main(ActivityThread.java:6145)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:892)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:782)
     Caused by: java.lang.ClassNotFoundException: Didn't find class "miui.os.Build" on path: DexPathList[[zip file "/data/app/com.miui.weather2-1/base.apk"],nativeLibraryDirectories=[/data/app/com.miui.weather2-1/lib/arm, /data/app/com.miui.weather2-1/base.apk!/lib/armeabi, /system/lib, /vendor/lib]]
        at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:380)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
        at com.miui.weather2.tools.ia.c(SourceFile:1) 
        at com.miui.weather2.WeatherApplication.onCreate(SourceFile:2) 
        at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1024) 
        at android.app.ActivityThread.handleBindApplication(ActivityThread.java:5429) 
        at android.app.ActivityThread.-wrap2(ActivityThread.java) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1550) 
        at android.os.Handler.dispatchMessage(Handler.java:102) 
        at android.os.Looper.loop(Looper.java:154) 
        at android.app.ActivityThread.main(ActivityThread.java:6145) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:892) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:782) 

⚡️pico不支持中文转换

I/TextToSpeech: Sucessfully bound to com.svox.pico
I/TextToSpeech: Connected to ComponentInfo{com.svox.pico/com.svox.pico.PicoService}
I/TextToSpeech: Set up connection to ComponentInfo{com.svox.pico/com.svox.pico.PicoService}

在这里插入图片描述

⚡️ NullPointerException

将语音引擎停用tts.getEngines().size()=0AudioUtil.initTTS(mc, tts_map.get(ttsListSp.getSelectedItem().toString()).toString());报错
2021-08-17 10:56:36.595 4764-4764/com.whn946.parrottongue E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.whn946.parrottongue, PID: 4764
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.whn946.parrottongue/com.whn946.parrottongue.DefaultModeActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String java.lang.Object.toString()' on a null object reference
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2781)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2859)
        at android.app.ActivityThread.-wrap11(Unknown Source:0)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1592)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:164)
        at android.app.ActivityThread.main(ActivityThread.java:6518)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
     Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String java.lang.Object.toString()' on a null object reference
        at com.whn946.parrottongue.DefaultModeActivity.getTtsListData(DefaultModeActivity.java:432)
        at com.whn946.parrottongue.DefaultModeActivity.init(DefaultModeActivity.java:102)
        at com.whn946.parrottongue.DefaultModeActivity.onCreate(DefaultModeActivity.java:72)

在这里插入图片描述

⚡️ FileNotFoundException

Android Q(10.0)版本 默认开启沙箱模式
非沙盒路径为外置存储下的其他路径,不允许访问
文件读写失败在manifest application中加上 android:requestLegacyExternalStorage=“true”
021-08-14 17:22:39.914 20241-20241/com.whn946.parrottongue E/TextToSpeech: Opening file /storage/emulated/0/0pcm/11-20210814172239.mp3 failed
    java.io.FileNotFoundException: open failed: EACCES (Permission denied)
        at android.os.ParcelFileDescriptor.openInternal(ParcelFileDescriptor.java:315)
        at android.os.ParcelFileDescriptor.open(ParcelFileDescriptor.java:220)
        at android.speech.tts.TextToSpeech$17.run(TextToSpeech.java:1842)
        at android.speech.tts.TextToSpeech$17.run(TextToSpeech.java:1832)
        at android.speech.tts.TextToSpeech$Connection.runAction(TextToSpeech.java:2312)
        at android.speech.tts.TextToSpeech.runAction(TextToSpeech.java:763)
        at android.speech.tts.TextToSpeech.runAction(TextToSpeech.java:753)
        at android.speech.tts.TextToSpeech.synthesizeToFile(TextToSpeech.java:1832)
        at android.speech.tts.TextToSpeech.synthesizeToFile(TextToSpeech.java:1889)
        at com.whn946.parrottongue.DefaultModeActivity$11$1.onClick(DefaultModeActivity.java:282)
        at androidx.appcompat.app.AlertController$ButtonHandler.handleMessage(AlertController.java:167)
        at android.os.Handler.dispatchMessage(Handler.java:107)
        at android.os.Looper.loop(Looper.java:224)
        at android.app.ActivityThread.main(ActivityThread.java:7592)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:539)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)

在这里插入图片描述
参考:2020-04-08 关于Android java.io.FileNotFoundException: open failed: EACCES (Permission denied)_zhuhuitao_struggle-CSDN博客
Android Q 默认开启沙箱模式 导致出现文件读写失败,在manifest application中加上 android:requestLegacyExternalStorage=“true”

在这里插入图片描述

在这里插入图片描述

⚡️其他思路

讯飞 百度 腾讯都有,也有免费额度
可以89天的时候 再申请一个,无缝对接,永远免费使用,一年只要申请4次就可以了
用后台接口,就不需要改app,超过免费额度,特定发音人还是需要单独收费
百度 腾讯的免费额度, 不限时间吧
放到服务端转好了,Windows内置有,实现就两行代码
小公司很多不用linux,而用Window的,成本更低
亚马逊有一定的免费额度
思必驰的可以,送一千条免费
试用的话基本不收费,量大的话才会产生费用,需要注册账号,配置appkey
开始会送一个免费的服务套餐,一千次调用
如果是文字转语音,可以用TTS,讯飞有免费的
它还是离线的
云之声
离线功能设置无效
http接口
带上文字http发一个get请求

⚡️

█ 附赠1:LeLeTextToVoice-OCR(图片转文字)

⚡️在Module的build.gradle文件中添加依赖和属性配置:

dependencies {
    implementation 'com.jakewharton.rxbinding:rxbinding:1.0.0'
    implementation 'com.rmtheis:tess-two:6.2.0'
}

⚡️封装工具OCRUtils :

public class OCRUtils {

    private static final String TAG = "OCR";
    @RequiresApi(api = Build.VERSION_CODES.N)
    public static String parseImageToString(Bitmap bitmap) throws IOException {
        if( bitmap == null ){
            return "";
        }

        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inSampleSize = 2;
        //图片旋转角度
        int rotate = 0;
        //先获取当前图像的方向,判断是否需要旋转
        //将bitmap转化为input
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
        InputStream isBm = new ByteArrayInputStream(baos.toByteArray());
        ExifInterface exif = new ExifInterface(isBm);
        int imageOriention = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION,
                ExifInterface.ORIENTATION_NORMAL);

        Log.i(TAG, "Current image orientation is " + imageOriention);

        switch (imageOriention){
            case ExifInterface.ORIENTATION_ROTATE_90:
                rotate = 90;
                break;
            case ExifInterface.ORIENTATION_ROTATE_180:
                rotate = 180;
                break;
            case ExifInterface.ORIENTATION_ROTATE_270:
                rotate = 270;
                break;
        }

        Log.i(TAG, "Current image rotate is " + rotate);

        //获取当前图片的宽和高
        int w = bitmap.getWidth();
        int h = bitmap.getHeight();

        //使用Matrix 矩阵对图片进行处理
        Matrix mtx = new Matrix();
        mtx.preRotate(rotate);

        //旋转图片
        bitmap = Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, false);
        bitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);

        //开始调用Tess函数进行识别
        TessBaseAPI baseAPI = new TessBaseAPI();
        baseAPI.setDebug(true);

        //使用默认语言初始化BaseApi
        baseAPI.init(Environment.getExternalStorageDirectory().getPath()+"/tesseract/", "eng");
        baseAPI.setImage(bitmap);

        // 获取返回值
        String recognizedText = baseAPI.getUTF8Text();
        Log.i(TAG, "exchanged : " + recognizedText);

        return recognizedText;
    }
}

⚡️使用(图片转文字) :

        RxView.clicks(findViewById(R.id.btn_ocr))
                .throttleFirst(500, TimeUnit.MILLISECONDS)
                .subscribe(new Action1<Void>() {
                    @RequiresApi(api = Build.VERSION_CODES.N)
                    @Override
                    public void call(Void aVoid) {
                        try {
                            String text = OCRUtils.parseImageToString(BitmapFactory.decodeResource(MainActivity.this.getResources(), R.mipmap.test));
                            Log.e("MainActivity","text2 ="+text);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                });

█ 附赠2:TextToMp3(收费,需要联网)

⚡️TextToMp3工具下载是一款文字转语音的工具,为你制作广告,有声小说,文档,案例。或者做一些自媒体节目。或者上传到有声小说,有声阅读平台都是非常不错的工具,推荐来下载体验。

⚡️需要联网,导出时,需要金币,金币需要充值收费
在这里插入图片描述

⚡️软件介绍
在这里插入图片描述

软件介绍
一款人气较高的软件。TextTomp3软件是一款文本转语音app,TextToMp3 app可以迅速将文字转化成语音,方便快捷,而且TextToMp3 app还支持外语配音,多语言支持,功能强大。
软件功能
* Text To Mp3支持多语种配音:英语配音、日语配音、韩语配音;
* Text To Mp3支持添加背景音乐;
* Text To Mp3支持录音功能;
* Text To Mp3支持mp3分享和导出;
* Text To Mp3支持文字转语音;
* Text To Mp3支持免费文字转语音(TTS)播放Mp3配音;
* Text To Mp3支持免费语音合成;
软件特色
1、广告配音:商场广告宣传配音,企业宣传配音,电影配音等;
2、语音合成:制作各种配音,小说配音,杂志,教科书阅读等;
3、广播配音:学校,企业,车站,机场和购物中心的广播;
4、多媒体配音:光盘解说、集团彩铃、电信、金融CTI的语音录制。
5、解说配音:企业专题片、建筑动画、工程标书解说等配音解说。
6、教学配音:电子词典、教材、电子图书、各类语音IC系列录制。

在这里插入图片描述
在这里插入图片描述


█ 相关资料

提示:这里是参考的相关文章

  1. Mr946/ParrotTongue: 文转音-安卓调用系统TTS实现文字转语音并保存为mp3音频文件。
  2. 2020-04-08 关于Android java.io.FileNotFoundException: open failed: EACCES (Permission denied)_zhuhuitao_struggle-CSDN博客
  3. 2020-10-19 Android 10 存储模型->requestLegacyExternalStorage_woai110120130的专栏-CSDN博客_requestlegacyexternalstorage
  4. 2018-08-20 TextToSpeech文字转语音、文字转音频文件并播放 - 灰信网(软件开发博客聚合):文字内容不能超过4000个字,可以分片保存音频
  5. 2018-09-12 android客户端ORC图片识别库tess_two的使用_隔壁小王的博客-CSDN博客
  6. 2016-05-03 文字转语音花费太多时间,而synthesizeToFile Android中 - VoidCC:使用Android内置TTS Engine合成mp3文件,文字转语音花费太多时间,我已经解决了这个问题,将整个文件转换为段落块,并将段落添加到TTS引擎并直接播放。
  7. 2017-02-06 LeLeTextToVoice: 将文字转换为语音:防止重复点击rxbinding、加载动画Android-SpinKit、OCR工具Tess-Two、科大讯飞Msc.jar
  8. TextToMp3工具下载|TextToMp3v2.0.10安卓版下载 - 99安卓游戏
  9. 2018-04-13 科大讯飞语音引擎3.0下载-科大讯飞引擎3.0apk下载v3.0 安卓版-绿色资源网
  10. 官网:离线语音合成 - 语音合成 - 讯飞开放平台
  11. 官网:TextToSpeech - synthesizeToFile | Android 开发者 | Android Developers
  12. 2018-03-17 Android文字转语音引擎(TTS)简单比较及下载_yingchengyou的博客-CSDN博客_com.google.android.tts
  13. 2012-02-03 Android中文语音合成(TTS)各家引擎对比_Yao.GUET-CSDN博客_pico tts
  14. 2021-05-20 Google Text下载2021安卓手机版_手机app免费下载
  15. 2013-06-08 原生安卓系统如何安装小米天气(MIUI天气)?_百度知道
  16. 官网:云知声语音开放平台使用指南]
  17. 2018-06-06 实例化一个新的TextToSpeech给一个NullPointer异常? - 问答 - 云+社区 - 腾讯云

█ 免责声明

博主分享的所有文章内容,部分参考网上教程,引用大神高论,部分亲身实践,记下笔录,内容可能存在诸多不实之处,还望海涵,本内容仅供学习研究使用,切勿用于商业用途,若您是部分内容的作者,不喜欢此内容被分享出来,可联系博主说明相关情况通知删除,感谢您的理解与支持!

提示:转载请注明出处:
https://blog.csdn.net/ljb568838953/article/details/119703057

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值