美文网首页PYNQ
给我儿子做个自动读故事的机器

给我儿子做个自动读故事的机器

作者: IEEE1364 | 来源:发表于2018-12-07 23:46 被阅读430次

    前言

    今天演示的例子是在将文字传送到讯飞的云平台进行语音合成,合成完毕后,返回语音,在pynq平台上将语音转化为合适的格式进行播放。这个东西可以给我儿子做个自动读书器,将来老子就不用天天给他讲故事了。哈哈哈,想想就很六,不过残酷的现实是得先找到孩子他妈。

    不扯闲话了,开始正式分析这个问题怎么做。
    将文字传送到讯飞的云平台很容易,只需要现在云端申请一个账号,建立一个应用,获取到key 和 id之后,按照官方开发文档并参照python demo就可以完成了。

    先打一波广告!

    讯飞的开放平台很好用,每天500次免费的使用,还算可以了,申请账号很方便。

    再黑一波竞争对手

    不像国内某SB搜索公司的人工智能平台,申请开发者账号的时候要填一堆信息,比美国签证还要麻烦,中间还强行要我安装他们的手机搜索APP进行人脸识别验证,一堆SB流程走完让我等审核的结果。结果尼玛,三个月了还是没给我。美国签证也只是Administrative Processing一下我,最终还是放我过去了啊。

    一、讯飞云语音合成的实现

    首先需要在讯飞开放平台上申请一个账户并建立一个应用,针对本设计我建立一个叫“电子书在线播放”的应用。在这里你可以看到APPID和APIKey这两个关键信息。


    image.png

    获取语音的代码如下:

    import base64
    import json
    import time
    import hashlib
    import urllib.request
    import urllib.parse
    
    # API请求地址、API KEY、APP ID等参数,提前填好备用
    api_url = "http://api.xfyun.cn/v1/service/v1/tts"
    API_KEY = "****************************************"# use your key
    APP_ID = "***********" # use your ID
    OUTPUT_FILE = "output.wav"    # 输出音频的保存路径,请根据自己的情况替换
    TEXT = "江山如画,一时多少豪杰"
    
    # Set Audio parameters
    Param = {
        "auf": "audio/L16;rate=16000",    #音频采样率
        "aue": "raw",    #音频编码,raw(生成wav)或lame(生成mp3)
        "voice_name": "xiaoyan",
        "speed": "50",    #语速[0,100]
        "volume": "77",    #音量[0,100]
        "pitch": "50",    #音高[0,100]
        "engine_type": "aisound"    #引擎类型。aisound(普通效果),intp65(中文),intp65_en(英文)
    }
    # 配置参数编码为base64字符串,过程:字典→明文字符串→utf8编码→base64(bytes)→base64字符串
    Param_str = json.dumps(Param)    #得到明文字符串
    Param_utf8 = Param_str.encode('utf8')    #得到utf8编码(bytes类型)
    Param_b64 = base64.b64encode(Param_utf8)    #得到base64编码(bytes类型)
    Param_b64str = Param_b64.decode('utf8')    #得到base64字符串
    
    # Build HTTP request header
    time_now = str(int(time.time()))
    checksum = (API_KEY + time_now + Param_b64str).encode('utf8')
    checksum_md5 = hashlib.md5(checksum).hexdigest()
    header = {
        "X-Appid": APP_ID,
        "X-CurTime": time_now,
        "X-Param": Param_b64str,
        "X-CheckSum": checksum_md5
    }
    # build HTTP Body
    body = {
        "text": TEXT
    }
    
    body_urlencode = urllib.parse.urlencode(body)
    body_utf8 = body_urlencode.encode('utf8')
    
    #Send HTTP POST request
    req = urllib.request.Request(api_url, data=body_utf8, headers=header)
    response = urllib.request.urlopen(req)
    
    # Get Result
    response_head = response.headers['Content-Type']
    if(response_head == "audio/mpeg"):
        out_file = open(OUTPUT_FILE, 'wb')
        data = response.read() # a 'bytes' object
        out_file.write(data)
        out_file.close()
        print('Get translation sucessfully,output file is ' + OUTPUT_FILE)
    else:
        print(response.read().decode('utf8'))
    

    说明:
    1.这段代码是在网上一个博客里面找的,参考链接如下:
    https://segmentfault.com/a/1190000013953185
    具体细节原文已经讲的比较清楚了。
    2.需要在应用的IP白名单里面将你的IP放进去,好像一般要等几分钟才能正式生效。只有白名单的IP才可正常连接讯飞开发平台获取数据。
    3.语音文件的格式要和我的保持一致,否则下面的代码有可能无法正确运行并得到结果

    二、对语音文件进行格式转化

    PYNQ的库只能支持4.8k采样率24bit 精度双通道wav格式的播放(好像什么pdm格式也行,没太研究)这里需要自己将讯飞云平台返回的wav格式文件进行转化,才能进行播放。
    根据前面的语音参数,我们获取到的音频是1.6k采样率,单声道,16bit。
    先将数据转化成24bit。

    import soundfile
    
    data, samplerate = soundfile.read('output.wav')
    soundfile.write('output_24bit.wav', data, samplerate, subtype='PCM_24')#Generate 24bit wave file
    

    这部分代码需要安装soundfile库到python3.6(PYNQ 用的就是3.6,不要装错)
    使用下面指令安装pip3

    sudo apt update
    sudo apt install python3-pip
    pip3.6 install --upgrade pip
    

    再安装soundfile库

    pip3.6 install soundfile
    

    如果运行pip3.6的时候返回找不到main。参考下面链接
    https://blog.csdn.net/accumulate_zhang/article/details/80269313
    对 /usr/bin/pip3进行下面修改即可

    from pip import __main__
    if __name__ == '__main__':
        sys.exit(__main__._main())
    

    转换完成后,再补齐成双通道,并且每个数据插入两次0,将采样率提升为4.8k。同时将文件头修改成正确的格式。代码如下:

    import wave
    import numpy as np
    import pylab as plt
    import struct
    
    #open file
    fin = wave.open("output_24bit.wav","rb")
    #read wave file heater get wave information
    params = fin.getparams()
    nchannels, sampwidth, framerate, nframes = params[:4]
    print(params)
    
    #read wave date
    str_data  = fin.readframes(nframes)
    
    buf = b''
    barr = bytearray(buf)
    
    for i in range(len(str_data)):
        barr.append(str_data[i])
        barr.append(str_data[i])
        barr.append(0)
        barr.append(0)
        barr.append(0)
        barr.append(0)
    
    p = bytes(barr)
    fout = wave.open("output_24bit_2channel_4k8.wav","wb")
    fout.setparams(params)
    fout.setframerate(4800)# set rate as 4k8
    fout.setnchannels(2)# set as 2channel wave
    fout.setnframes(nframes+int(len(str_data)/2)*5)#modify frame length to 4k8 2channel
    fout.writeframes(p)
    
    print('Generate wav file ', "output_24bit_2channel_4k8.wav")
    
    fout.close()
    

    现在这个使用简单插值的方式来增加采样率,噪音比较大,音量比较小,后面需要改进一下。

    三、语音播放

    接下来的工作就简单了使用base overlay 里面的audiomm模块就可以播放了。代码如下:

    from pynq.overlays.base import BaseOverlay
    base = BaseOverlay("base.bit")
    pAudio = base.audio
    pAudio.select_microphone()# use microphne
    
    path ="/home/xilinx/jupyter_notebooks/base/mydesign/"+ "output_24bit_2channel_4k8.wav"
    print(pAudio.info(path))
    pAudio.load(path)
    
    pAudio.play()
    

    后记

    使用PYNQ开发很方面,而且很多代码可以直接在PC上直接调试好,在复制到PYNQ上执行,加快调试速度。这篇文章里面的语音获取和文件格式修改都是在PC上完成的,只有最后一部分需要硬件,才在PYNQ上调试了一下。

    这个设计只是一个demo 为我们演示如何迅速将底层硬件和云端进行连接,迅速完成以前我们需要花很长时间才能玩的设计。将云端和硬件连接起来有好多事情可以做的,可以极大地拓展我们的应用。

    现在这个代码里面语音格式转换太耗费时间,将其代码用C实现或者用逻辑资源来实现,才是最大限度发挥PYNQ的优势,后面有时间再搞吧。毕竟还不知道孩子他妈在哪儿呢!

    相关文章

      网友评论

        本文标题:给我儿子做个自动读故事的机器

        本文链接:https://www.haomeiwen.com/subject/uxhfhqtx.html