基于Android的文本语音朗读器的设计与实现(有声小说APP)

摘 要
随着时代的发展,越来越多的信息正在产生,人们对信息的获取也越来越重视,从传统的看书到现在的网络,看视频,听广播。多年来,人们获取信息的方式发生了变化。随着人们进入信息时代和网络文学的发展,人们越来越依赖手机获取信息,在人们的生活和娱乐中,手机阅读已经成为人们获取信息的新方式。手机阅读是新时代获取信息的一种新方式,但长时间在有手机的地方用手机看书对人的眼睛造成负担,盲人无法使用,难度较大获取信息,给他们带来不便。
随着时代的进步,科技的进步,以及计算机技术的飞速发展,今天的文本到语音转换不会是一个大问题。将文本文档转换为语音也成为了一个发展方向。本系统的设计和开发是开发一个基于Android的文本语音阅读器。
文字转文本语音朗读器基于Android环境运行,融合文字转语音模型,实现移动网络环境下的文档语音阅读处理服务。 “导入文本文件、解码文档、输入用户文本、阅读文本、切换语言、调节语速、调节语音、调节音量、暂停、播放、后退、前进、界面换肤、保存文档”功能。等等。系统总体设计和功能设计经过完善和测试,适应性和实用性强,有良好的用户体验。
关键词:Android;语音;朗读器;智能有声;有声文本
Abstract
With the development of The Times, more and more information is being generated, and people pay more and more attention to the acquisition of information, from the traditional reading to the current Internet, watching videos and listening to the radio.Over the years, the way people access their information has changed.As people enter the information age and the development of network literature, people rely more and more on mobile phones for information. In people’s life and entertainment, mobile phone reading has become a new way for people to obtain information.Mobile phone reading is a new way to obtain information in the new era, but reading with mobile phones with mobile phones for a long time causes a burden on people’s eyes, and the blind people cannot use it, so it is difficult to obtain information, which brings inconvenience to them.
With the progress of The Times, the progress of technology, and the rapid development of computer technology, today’s text to speech conversion will not be a big problem.Converting text documents into voice has also become a development.The system was designed and developed for the development of a text-speech reader based on Android.
The text-to-voice system runs based on the Android environment and integrates the text-to-voice model to realize the document voice reading and processing service in the mobile network environment.“Import text files, decode documents, enter user text, read text, switch language, adjust language, adjust speed, adjust voice, adjust volume, pause, play, back, forward, interface skin, save documents” function.wait a minute.The overall design and functional design of the system have been improved and tested, with strong adaptability and practicability, and a good user experience.
Key words: Android; voice; reader; intelligent audio; audio text
目录
摘 要 I
Abstract II
1绪论 1
1.1选题背景及意义 1
1.1.1选题背景 1
1.1.2选题意义 2
1.2研究现状及发展前景 2
1.2.1市场现状 2
1.2.2技术现状 4
1.2.3发展前景 5
1.4研究内容及创新 5
1.4.1研究内容 5
1.4.2创新设计 6
2系统开发相关技术 7
2.1技术方案 7
2.2框架及语言简介 8
2.2.1开发语言JavaSE 8
2.2.2 Spring框架 9
2.2.3 Springmvc框架 10
2.2.4 Mybatis 12
2.2.5 Android平台架构 12
2.2.6 Eclipse及ADT介绍 15
2.2.7第三方语音库TTS选择 15
2.2 数据库技术 16
3系统分析 18
3.1需求分析解决的主要问题 18
3.2系统功能需求 18
3.3系统非功能需求 20
4 系统设计 21
4.1基本简介 21
4.2系统结构图 21
4.3概要设计 21
4.3.1各功能模块设计 21
4.3.2产品功能 22
4.4软件架构设计 23
4.4.1用例视图 23
4.4.2逻辑视图 27
4.4.3进程视图 36
4.4.4部署视图 37
4.4.5实现视图 38
4.4.6数据视图 39
4.5核心算法设计 39
4系统实现 41
4.1系统APP客户端实现 41
4.2系统网页端管理实现 45
5系统测试 46
5.1系统错误 46
5.1.1加载布局XML无效 46
5.1.2制作截断无效 46
5.1.3语音识别中文无效 47
5.1.4系统资源找不到 47
5.1.5制作服务截取消息传送问题 47
5.2系统优化 48
5.2.1 XML布局优化 48
5.2.2代码提示String修改优化 48
6总结与展望 49
6.1论文总结 49
6.2研究展望 49
参考文献 51
致 谢 53
3系统分析
要做一个符合用户需求的软件,对用户进行需求分析必不可少。需求分析需要弄清楚用户最终需要解决哪些问题,开发出的系统要为用户提供什么样的功能,什么样的操作界面和运行环境。
3.1需求分析解决的主要问题
在传统的手机应用软件中,对于语音朗读的处理都是相对比较薄弱,在Android平台上的有声朗读的软件也是寥寥无几。解决的主要问题是本课题要完成哪些现实有效的功能。
要实现一个软件,首先应该进行需求分析,这样才能令设计出的软件满足用户的各项功能。下面就对本课题的设计进行需求分析。
3.2系统功能需求
本项目旨在开发一款基于人工智能的文本语音朗读器产品,结合机器朗读的高效率及人工录制的高品质特性,将文本材料加工为拟人的语音材料,为听众提供更加良好的听书体验。
本项目预计实现的所有功能需求如下:
在这里插入图片描述

3.1 功能需求图
1)用户注册
a)用户注册时需填写相关信息(包括用户名、密码、姓名、性别、邮件地址)。
b)要对用户的手机号码和电子邮箱地址的格式有效性和唯一性进行校验。
c)用户注册后,向用户注册邮箱发送激活邮件,邮件中包含激活地址,点击该地址完成激活。
d)只有完成激活的用户才能登录,否则提示用户必须先激活
2)用户登录
3)管理员管理用户信息
4)管理员管理文本语音朗读器信息
5)用户信息管理
a)个人信息维护(包括用户名、密码、姓名、性别、邮件地址)
b)个人隐私维护(设置其他用户访问权限,包括个人信息,收藏夹,收听历史)
c)创建的文本语音朗读器,可以添加、查找、删除
d)收听过的文本语音朗读器,可以添加、查找、删除
e)收藏夹,可以添加、查找、删除
6)通过文本制作文本语音朗读器
a)用户上传文本,根据文本生成语音内容
b)同时对于文本内容进行情感分析和语义分析,从而给文本语音朗读器提供符合文本感情、 内容的背景音乐和符合文本上下文的声音音效。
7)有声阅读
a)收听自己制作的文本语音朗读器
b)分享发布自己制作的文本语音朗读器
c)搜索、浏览、收藏、收听其他用户制作的文本语音朗读器
8)面向文本语音朗读器朗读者,通过音频生成文本语音朗读器
a)朗读者根据文本朗读并录制音频
b)上传自己录制的文本语音朗读器音频,对于音频进行调音降噪处理
c)应用使用机器学习技术分析音频,自动为音频匹配符合音频感情、内容的背景音乐和符合音频中文本上下文的声音音效(同基本需求6.b)。
9)面向应用用户,系统学习用户的阅读偏好,并根据偏好进行作品推荐。
提供用户输入的区域,是的用户能输入文字;提供ReadFile功能,能读取系统内部开放权限的的TXT的文本内容;提供对用户输入的文字,或者是系统读出的TXT的文本进行朗读;提供用户输入的接口,用户可以输入语音;提供给语音合成返回的处理功能。
本文转载自:http://www.biyezuopin.vip/onews.asp?id=16467

package com.run.tools;

import com.baidu.aip.speech.AipSpeech;
import com.hankcs.hanlp.classification.classifiers.IClassifier;
import com.hankcs.hanlp.classification.classifiers.NaiveBayesClassifier;
import com.hankcs.hanlp.classification.models.NaiveBayesModel;
import com.hankcs.hanlp.corpus.io.IOUtil;
import com.hankcs.hanlp.mining.word2vec.DocVectorModel;
import com.hankcs.hanlp.mining.word2vec.WordVectorModel;
import net.sf.json.JSONObject;
import org.json.JSONArray;

import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class asrapi {
    private static  WordVectorModel wordVectorModel;
    static {
        try {
            wordVectorModel = new WordVectorModel("E:\\download\\word2vec_c");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    private static List<String> dictc= dict.init();
    private static DocVectorModel docVectorModel=new DocVectorModel(wordVectorModel);
    private static deom2 ffmpegx;
    private static final String MODEL_PATH = "D:\\HanLP\\data\\model\\sen\\classification-sen-model.ser";
    public static final String CORPUS_FOLDER =  "D:\\HanLP\\data\\dictionary\\sen\\ChnSentiCorp情感分析酒店评论";
    public static void asr(AipSpeech client) throws Exception {
        // 对本地语音文件进行识别
        //String path = "E:\\1-1\\1-1.pcm_69640-84499_A.pcm";
        //org.json.JSONObject asrRes = client.asr(path, "pcm", 16000, null);
        //System.out.println(asrRes);
        ArrayList<String> tmp=getAllFileName("E:\\1-1");
        ArrayList<pcmfile> pcmfiles=new ArrayList<>();
        String Path="E:\\";
        String MusicPath="D:\\index\\handle";
        String BgmPath="E:\\BGM";
        Integer positive=0;
        Integer negative=0;
        IClassifier classifier = new NaiveBayesClassifier(trainOrLoadModel());
        for (int i=0;i<tmp.size();i++)
        {
            String str=tmp.get(i);
            Double starttime=0.0;
            Double endtime=0.0;
            Boolean flag=true;
            String filename=str.substring(0,str.length()-4);
            Integer delim1=str.indexOf("_");
            Integer delim2=str.indexOf("-",delim1);
            if (delim1==-1||delim2==-1) break;
            String tmp1=str.substring(delim1+1,delim2);
            starttime=Double.valueOf(tmp1);
            delim1=str.indexOf("_",delim2);
            if (delim1==-1||delim2==-1) break;
            tmp1=str.substring(delim2+1,delim1);
            endtime=Double.valueOf(tmp1);
            delim2=str.indexOf(".",delim1);
            tmp1=str.substring(delim1+1,delim2);
            if (delim1==-1||delim2==-1) break;
            if (tmp1=="A") flag=true;
            System.out.println(tmp1+flag);
            org.json.JSONObject asrRes = client.asr("E:\\1-1\\"+str, "pcm", 16000, null);
            while (!asrRes.getString("err_msg").equals("success.")) {
                asrRes = client.asr("E:\\1-1\\" + str, "pcm", 16000, null);
                System.out.println(asrRes.toString());
            }
            double max=0;
            String sug="";
            JSONArray res=asrRes.getJSONArray("result");
            List<Object> strres=res.toList();
            String parse=strres.get(0).toString();
            System.out.println(parse);
            System.out.println(classifier.classify(parse));
            System.out.println(classifier.classify(parse).equals("正面"));
            if (classifier.classify(parse).equals("正面")) positive++;
            else negative++;
            //System.out.println(classifier.classify(parse));
                for (int k = 0; k < dictc.size(); k++) {
                    if (docVectorModel.similarity(parse, dictc.get(k)) > max) {
                        max = docVectorModel.similarity(parse, dictc.get(k));
                        sug = dictc.get(k);
                    }
                }

            if (flag==true) {
                System.out.println(res + "has bgm" +sug+max);
            }
            pcmfile tmpfile=new pcmfile();
            if (max>0.7) {
                    File file = new File(filename+"mf.mp3");
                    if (!file.exists()){
                        ffmpegx.mofidyvoice(MusicPath+"\\"+sug+"\\"+sug+".mp3",MusicPath+"\\"+sug+"\\"+sug+"mf.mp3",-30-ffmpegx.processFLV(MusicPath+"\\"+sug+"\\"+sug+".mp3"));
                    }
                ffmpegx.addsoundpcm(Path + "1-1" + "\\" + filename+".pcm", MusicPath+"\\"+sug+"\\"+sug+"mf", Path + "1-1" + "\\" + filename+"-f.pcm");
                tmpfile.setName(filename+"-f");
                tmpfile.setStarttime(starttime);
            }
            else {
                tmpfile.setName(filename);
                tmpfile.setStarttime(starttime);
            }
            pcmfiles.add(tmpfile);
        }
        System.out.println(positive.toString()+"000"+negative.toString());
        Collections.sort(pcmfiles,new pcmfileComparetor());
        for (int i=0;i<pcmfiles.size();i++)
        {
            byte[] ret=getBytes(Path+"1-1\\"+pcmfiles.get(i).getName().toString()+".pcm");
            getFile(ret,Path,"1-1"+"-f.pcm");
        }
        Double percent=((positive-negative))*1.0/(positive+negative);
        Integer flag=0;
        System.out.println(percent);
        if (Math.abs(percent)<=0.1) flag=3;
        else
        if (percent>0) flag=2;
        else flag=1;
        System.out.println(flag);
        String bgm=selectbgm(flag);
        System.out.println(bgm);
        ffmpegx.mergepcm(Path+"1-1"+"-f.pcm",bgm,Path+"1-1"+"-f-v.pcm");
        // 对语音二进制数据进行识别
        //byte[] data = Util.readFileByBytes(path);     //readFileByBytes仅为获取二进制数据示例
        //org.json.JSONObject asrRes2 = client.asr(data, "pcm", 16000, null);
        //System.out.println(asrRes2);

    }
    public static void main(String[] args) throws Exception {
        AipSpeech aipSpeech = new AipSpeech("16720362","drYw1Ut4GQRAeZSC2FMqbNEg", "36Oz5GXBqYWIMC6QfG9GG4AGrVqO0CUI");
        asr(aipSpeech);
    }
    public static ArrayList<String> getAllFileName(String path)
    {
        ArrayList<String> res=new ArrayList<>();
        File file = new File(path);
        File [] files = file.listFiles();
        String [] names = file.list();
        if(names != null)
            res.addAll(Arrays.asList(names));
        return res;
    }
    /*public static Boolean parse_file(String str,Double st,Double en,Boolean fl)
    {
        Integer delim1=str.indexOf("_");
        Integer delim2=str.indexOf("-",delim1);
        if (delim1==-1||delim2==-1) return false;
        String tmp1=str.substring(delim1+1,delim2);
        System.out.println(tmp1+delim1+delim2);
        st=Double.valueOf(tmp1);
        delim1=str.indexOf("_",delim2);
        if (delim1==-1||delim2==-1) return false;
        tmp1=str.substring(delim2+1,delim1);
        System.out.println(tmp1+delim1+delim2);
        en=Double.valueOf(tmp1);
        delim2=str.indexOf(".",delim1);
        tmp1=str.substring(delim1+1,delim2-1);
        if (delim1==-1||delim2==-1) return false;
        fl=Boolean.valueOf(tmp1);
        return true;
    }*/
    public static void getFile(byte[] bfile, String filePath, String fileName) {
        BufferedOutputStream bos = null;
        FileOutputStream fos = null;
        File file = null;
        try {
            File dir = new File(filePath);
            if (!dir.exists() && dir.isDirectory()) {// �ж��ļ�Ŀ¼�Ƿ����
                dir.mkdirs();
                System.out.println("NOT FIND");
            }
            file = new File(filePath + "/" + fileName);
            fos = new FileOutputStream(file,true);
            bos = new BufferedOutputStream(fos);
            bos.write(bfile);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (bos != null) {
                try {
                    bos.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
        }
    }
    public static byte[] getBytes(String filePath){
        byte[] buffer = null;
        try {
            File file = new File(filePath);
            FileInputStream fis = new FileInputStream(file);
            ByteArrayOutputStream bos = new ByteArrayOutputStream(1000);
            byte[] b = new byte[1000];
            int n;
            while ((n = fis.read(b)) != -1) {
                bos.write(b, 0, n);
            }
            fis.close();
            bos.close();
            buffer = bos.toByteArray();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return buffer;
    }
    private static NaiveBayesModel trainOrLoadModel() throws IOException {
        NaiveBayesModel model = (NaiveBayesModel) IOUtil.readObjectFrom(MODEL_PATH);
        if (model != null) return model;
        File corpusFolder = new File(CORPUS_FOLDER);
        System.out.println(corpusFolder.isDirectory());
        if (!corpusFolder.exists() || !corpusFolder.isDirectory()) {
            System.err.println("没有文本分类语料,请阅读IClassifier.train(java.lang.String)中定义的语料格式与语料下载:" +
                    "https://github.com/hankcs/HanLP/wiki/%E6%96%87%E6%9C%AC%E5%88%86%E7%B1%BB%E4%B8%8E%E6%83%85%E6%84%9F%E5%88%86%E6%9E%90");
            System.exit(1);
        }
        IClassifier classifier = new NaiveBayesClassifier(); // 创建分类器,更高级的功能请参考IClassifier的接口定义
        classifier.train(CORPUS_FOLDER);                     // 训练后的模型支持持久化,下次就不必训练了
        model = (NaiveBayesModel) classifier.getModel();
        IOUtil.saveObjectTo(model, MODEL_PATH);
        return model;
    }
    public static String selectbgm(Integer label) throws Exception {
        String Path="E:\\";
        String Filename="BGM";
        Filename=Filename+"\\"+label.toString();
        System.out.println(Path+Filename);
        File file=new File(Path+Filename);
        File [] files=file.listFiles();
        int size=files.length;
        int random=(int)(Math.random()*size+1);
        System.out.println(files[random].getPath());
        return files[random].getPath();
    }
}

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值