欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android语音播报商家收款及相关TTS语音文件合成

程序员文章站 2022-04-30 09:25:04
...

主要思路: 1.处理需要播报的金额 2.合成语音文件,对金额播报

其实很简单,两行代码直接搞定

List<String> list = new VoiceTemplate()
                   .prefix("success")
                  .numString(money)
                   .suffix("yuan")
                    .gen();
VoiceSpeaker.getInstance().speak(list);

步骤1.对播报的金额通过小数点判断,拆解为整数和小数部分

import android.text.TextUtils;

import java.util.ArrayList;
import java.util.List;


public class VoiceTemplate {

    private static final String DOT = ".";
    private String numString;
    private String prefix;
    private String suffix;
    private static final char[] NUM = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
    private static final char[] CHINESE_UNIT = {'元', '拾', '佰', '仟', '万', '拾', '佰', '仟', '亿', '拾', '佰', '仟'};
    
    public VoiceTemplate() {

    }

    public VoiceTemplate prefix(String prefix) {
        this.prefix = prefix;
        return this;
    }

    public VoiceTemplate suffix(String suffix) {
        this.suffix = suffix;
        return this;
    }

    /**
     * 处理执行的金额,目前只支持亿级别,想支持更大数据,自己改
     *
     * @param numString
     * @return
     */
    public VoiceTemplate numString(String numString) {
        this.numString = numString;
        return this;
    }

    public List<String> gen() {
        return genVoiceList();
    }


    private List<String> genVoiceList() {
        List<String> result = new ArrayList<>();
        if (!TextUtils.isEmpty(prefix)) {
            result.add(prefix);
        }
        if (!TextUtils.isEmpty(numString)) {
            result.addAll(genReadableMoney(numString));
        }

        if (!TextUtils.isEmpty(suffix)) {
            result.add(suffix);
        }
        return result;
    }

    /**
     * 处理小数点之前和之后的数据
     *
     * @param numString
     * @return
     */
    private List<String> genReadableMoney(String numString) {
        List<String> result = new ArrayList<>();
        if (!TextUtils.isEmpty(numString)) {
            if (numString.contains(DOT)) {
                String integerPart = numString.split("\\.")[0];
                String decimalPart = numString.split("\\.")[1];
                List<String> intList = readIntPart(integerPart);
                List<String> decimalList = readDecimalPart(decimalPart);
                result.addAll(intList);
                if (!decimalList.isEmpty()) {
                    result.add("dot");
                    result.addAll(decimalList);
                }
            } else {
                result.addAll(readIntPart(numString));
            }
        }
        return result;
    }

    private List<String> readDecimalPart(String decimalPart) {
        List<String> result = new ArrayList<>();
        if (!"00".equals(decimalPart)) {
            char[] chars = decimalPart.toCharArray();
            for (char ch : chars) {
                result.add(String.valueOf(ch));
            }
        }
        return result;
    }

    private List<String> readIntPart(String integerPart) {
        List<String> result = new ArrayList<>();
        String intString = readInt(Integer.parseInt(integerPart));
        int len = intString.length();
        for (int i = 0; i < len; i++) {
            char current = intString.charAt(i);
            if (current == '拾') {
                result.add("ten");
            } else if (current == '佰') {
                result.add("hundred");
            } else if (current == '仟') {
                result.add("thousand");
            } else if (current == '万') {
                result.add("ten_thousand");
            } else if (current == '亿') {
                result.add("billion");
            } else {
                result.add(String.valueOf(current));
            }
        }
        return result;
    }
    
    /**
     * 返回关于钱的中文式大写数字,支仅持到亿
     */
    public static String readInt(int moneyNum) {
        String res = "";
        int i = 0;
        if (moneyNum == 0) {
            return "0";
        }
        if (moneyNum == 10) {
            return "拾";
        }
        if (moneyNum > 10 && moneyNum < 20) {
            return "拾" + moneyNum % 10;
        }
        while (moneyNum > 0) {
            res = CHINESE_UNIT[i++] + res;
            res = NUM[moneyNum % 10] + res;
            moneyNum /= 10;
        }
        return res.replaceAll("0[拾佰仟]", "0")
                .replaceAll("0+亿", "亿").replaceAll("0+万", "万")
                .replaceAll("0+元", "元").replaceAll("0+", "0")
                .replace("元", "");
    }
}

步骤2.播报金额及相关TTS文件合成


import android.content.res.AssetFileDescriptor;
import android.content.res.AssetManager;
import android.media.MediaPlayer;

import java.io.IOException;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class VoiceSpeaker {

    private static VoiceSpeaker sInstance;
    private ExecutorService service;

    private VoiceSpeaker() {
        service = Executors.newCachedThreadPool();
    }
    
    public static synchronized VoiceSpeaker getInstance() {
        if (sInstance == null) {
            sInstance = new VoiceSpeaker();
        }
        return sInstance;
    }

    public void speak(final List<String> list) {
        if (service != null) {
            service.execute(new Runnable() {
                @Override
                public void run() {
                    start(list);
                }
            });
        }
    }

    /**
     * android自带MediaPlayer进行语音播报,简单方便
     * @param list
     */
    private void start(final List<String> list) {
        synchronized (this) {//防止混合播报
            final CountDownLatch latch = new CountDownLatch(1);
            MediaPlayer player = new MediaPlayer();
            if (list != null && list.size() > 0) {
                final int[] counter = {0};
                String path = String.format("sound/tts_%s.mp3", list.get(counter[0]));
                AssetFileDescriptor fd = null;
                try {
                    //加载合成好的本地TTS语音文件
                    fd = getAssetFileDescription(path);
                    player.setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getLength());
                    player.prepareAsync();
                    player.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
                        @Override
                        public void onPrepared(MediaPlayer mp) {
                            mp.start();
                        }
                    });
                    player.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
                        @Override
                        public void onCompletion(MediaPlayer mp) {
                            mp.reset();
                            counter[0]++;
                            if (counter[0] < list.size()) {
                                try {
                                    AssetFileDescriptor fileDescriptor =getAssetFileDescription(String.format("sound/tts_%s.mp3", list.get(counter[0])));
                                    mp.setDataSource(fileDescriptor.getFileDescriptor(), fileDescriptor.getStartOffset(), fileDescriptor.getLength());
                                    mp.prepare();
                                } catch (IOException e) {
                                    e.printStackTrace();
                                    latch.countDown();
                                }
                            } else {
                                mp.release();
                                latch.countDown();
                            }
                        }
                    });
                } catch (IOException e) {
                    e.printStackTrace();
                    latch.countDown();
                } finally {
                    if (fd != null) {
                        try {
                            fd.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
            try {
                latch.await();
                this.notifyAll();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 资源管理器加载对应语音文件
     * @param filename
     * @return
     * @throws IOException
     */
    public static AssetFileDescriptor getAssetFileDescription(String filename) throws IOException {
        AssetManager manager = BaseApp.getContext().getAssets();
        return manager.openFd(filename);
    }
}

getContext全局均可使用

public class BaseApp extends MultiDexApplication {

    private static Application instance;

    @Override
    public void onCreate() {
        super.onCreate();
        instance = this;
    }

    public static Application getContext() {
        return instance;
    }
}

步骤3.来 来 来,注意了,敲黑板了,上面是代码部分,下面进行语音合成,不过也是很easy的啦

百度合成TT文件:http://ai.baidu.com/tech/speech/tts 语速 音色等相关因素自己根据喜好和需求来自定义,你看多简单,将合成好的tts文件放在项目中,如下所示

Android语音播报商家收款及相关TTS语音文件合成

如何合成所需要的语音文件

Android语音播报商家收款及相关TTS语音文件合成