帖子

[经验分享] Python直接调用msc.dll完成tts合成并获取音频(指针方式)

[复制链接]
  • TA的每日心情
    开心
    2017-7-18 09:18
  • 签到天数: 1 天

    [LV.1]初来乍到

    1573329  楼主| RYHAN 发表于 2016-9-21 15:27:56 1#
    本帖最后由 RYHAN 于 2018-5-3 21:01 编辑

    这几天参照demo 的 c++代码完成python调用msc.dll,在获取void* 指针音频数据时,卡了我很久,直接使用缓冲区加指针实现音频读取,论坛有其他方式实现,会更简单
    1. data = string_at(pdata, audio_len.value)
    复制代码



    代码很简短,如下(没找到插入代码的控件。。。)

    1. #! /usr/bin/env python
    2. # coding=utf-8

    3. __author__ = 'ryhan'


    4. # 以下代码解决输出乱码问题
    5. import sys
    6. # print sys.getdefaultencoding()
    7. reload(sys)
    8. sys.setdefaultencoding('utf-8')
    9. # print sys.getdefaultencoding()

    10. from ctypes import *
    11. import time
    12. import struct


    13. sys.path.append('.')

    14. dll = windll.LoadLibrary("msc.dll")

    15. # print dll.MSPLogin
    16. # print dll.QTTSSessionBegin
    17. # print dll.QTTSTextPut
    18. # print dll.QTTSAudioGet
    19. # print dll.QTTSSessionEnd

    20. uname = "973214924@qq.com"
    21. upass = ""

    22. login_params = "appid = 自己的id, work_dir = ."
    23. session_begin_params = "voice_name = xiaoyan, text_encoding = utf8, sample_rate = 16000, speed = 50, volume = 50, pitch = 50, rdn = 2"

    24. MSP_SUCCESS = 0

    25. MSP_TTS_FLAG_STILL_HAVE_DATA = 1
    26. MSP_TTS_FLAG_DATA_END = 2
    27. MSP_TTS_FLAG_CMD_CANCELED = 4

    28. filename = "tts_sample.wav"
    29. text = "亲爱的用户,您好,这是一个语音合成示例,感谢您对科大讯飞语音技术的支持!科大讯飞是亚太地区最大的语音上市公司,股票代码:002230"
    30. print text
    31. # text = "hello"

    32. class Msp:
    33.     def __init__(self):
    34.         pass

    35.     def login(self):
    36.         ret = dll.MSPLogin(None, None, login_params)
    37.         print('MSPLogin =>'), ret

    38.         pass

    39.     def tts(self, text, filename, session_begin_params):
    40.         ret = c_int()
    41.         sessionID = dll.QTTSSessionBegin(session_begin_params, byref(ret))
    42.         print 'QTTSSessionBegin => sessionID:', sessionID, 'ret:', ret.value

    43.         ret = dll.QTTSTextPut(sessionID, text, len(text), None)
    44.         print 'QTTSTextPut => ret:', ret

    45.         audio_len = c_int()
    46.         synth_status = c_int()
    47.         getret = c_int()

    48.         wavFile = open(filename, 'wb')

    49.         print 'QTTSAudioGet => ',

    50.         while True:

    51.             # print '.',

    52.             dll.QTTSAudioGet.restype = POINTER(c_ushort * (1024 * 1024))
    53.             data = dll.QTTSAudioGet(sessionID, byref(audio_len), byref(synth_status), byref(getret))
    54.             print 'QTTSAudioGet => audio_len:', audio_len, 'synth_status:', synth_status, 'getret:', getret

    55.             if getret.value != MSP_SUCCESS:
    56.                 print '!MSP_SUCCESS'
    57.                 break

    58.             if data:
    59.                 i = -1
    60.                 while i < audio_len.value / 2:
    61.                     i += 1
    62.                     # 遍历指针获取数据 然后转换为byte写入到文件
    63.                     d = data.contents[i]
    64.                     if d:
    65.                         bytes = struct.pack('<H', d)
    66.                         wavFile.write(bytes)
    67.                     else:
    68.                         bytes = struct.pack('<H', 0)
    69.                         wavFile.write(bytes)

    70.                 print i

    71.             if synth_status.value == MSP_TTS_FLAG_DATA_END:
    72.                 print 'MSP_TTS_FLAG_DATA_END'
    73.                 break

    74.             time.sleep(0.05)

    75.         wavFile.close()
    76.         ret = dll.QTTSSessionEnd(sessionID, "Normal")
    77.         print 'QTTSSessionEnd => ret:', ret


    78.     pass


    79. if __name__ == "__main__":
    80.     msp = Msp()

    81.     msp.login()
    82.     msp.tts(text, filename, session_begin_params)
    复制代码

    IflytekYun.zip

    4.8 MB, 下载次数: 820

    评分

    参与人数 1语点 +10 收起 理由
    栗子讲究 + 10 很给力!

    查看全部评分

    iflytek-小黑 发表于 2016-9-21 16:27:34
    2#
    6666
    使用道具 举报 回复
    李刚天行健 发表于 2016-9-26 15:39:13
    3#
    似乎有问题,不能用!
    使用道具 举报 回复
    Reidzhang 发表于 2016-9-27 13:31:52
    4#
    给力,我想问下这能加音频头数据吗。。这样可以直接生成wav的音频吗。谢谢
    使用道具 举报 回复
    李刚天行健 发表于 2016-9-28 16:53:01
    5#
    Reidzhang 发表于 2016-9-27 13:31
    给力,我想问下这能加音频头数据吗。。这样可以直接生成wav的音频吗。谢谢
    ...

    我用python调用总是出现10407错误。


    dll = windll.LoadLibrary("d:/msc_x64.dll")

    login_params = "appid=57e252ab,work_dir=."
    ret = dll.MSPLogin(None, None, login_params)

    总是出现10407错误。
    这个appid和msc_x64.dll
    在c语言调试就是Ok的。

    请问,您是怎么调试的呢?
    使用道具 举报 回复
    Reidzhang 发表于 2016-10-18 09:40:37
    6#
    李刚天行健 发表于 2016-9-28 16:53
    我用python调用总是出现10407错误。

    不好意思,才看见。我当时是直接复制的代码。然后我电脑是32位的,你可以网上下个最新的dll试试。
    使用道具 举报 回复
     楼主| RYHAN 发表于 2016-10-28 17:02:43
    7#
    Reidzhang 发表于 2016-9-27 13:31
    给力,我想问下这能加音频头数据吗。。这样可以直接生成wav的音频吗。谢谢
    ...

    生成音频的话,建议用python 的 wave 包
    完整代码如下:
    1. #! /usr/bin/env python
    2. # coding=utf-8

    3. __author__ = 'ryhan'


    4. # 以下代码解决输出乱码问题
    5. import sys
    6. # print sys.getdefaultencoding()
    7. reload(sys)
    8. sys.setdefaultencoding('utf-8')
    9. # print sys.getdefaultencoding()

    10. from ctypes import *
    11. import time
    12. import wave


    13. sys.path.append('.')

    14. dll = windll.LoadLibrary("msc.dll")

    15. uname = "973214924@qq.com"
    16. upass = ""

    17. framerate = 16000

    18. login_params = "appid = 57d10f01, work_dir = ."
    19. session_begin_params = "voice_name = xiaoyan, text_encoding = utf8, sample_rate = 16000, speed = 50, volume = 50, pitch = 50, rdn = 2"

    20. MSP_SUCCESS = 0
    21. MSP_TTS_FLAG_STILL_HAVE_DATA = 1
    22. MSP_TTS_FLAG_DATA_END = 2
    23. MSP_TTS_FLAG_CMD_CANCELED = 4

    24. filename = "tts_sample.wav"
    25. text = "亲爱的用户,您好,这是一个语音合成示例,感谢您对科大讯飞语音技术的支持!科大讯飞是亚太地区最大的语音上市公司,股票代码:002230"
    26. print 'text:', text


    27. class Msp:
    28.     def __init__(self):
    29.         pass

    30.     def login(self):
    31.         ret = dll.MSPLogin(uname, upass, login_params)
    32.         print('MSPLogin =>'), ret

    33.         pass

    34.     def tts(self, text, filename, session_begin_params):
    35.         ret = c_int()
    36.         sessionID = dll.QTTSSessionBegin(session_begin_params, byref(ret))
    37.         print 'QTTSSessionBegin => sessionID:', sessionID, 'ret:', ret.value

    38.         ret = dll.QTTSTextPut(sessionID, text, len(text), None)
    39.         print 'QTTSTextPut => ret:', ret

    40.         audio_len = c_int()
    41.         synth_status = c_int()
    42.         getret = c_int()

    43.         wavFile = wave.open(r"tts_sample.wav", "wb")
    44.         # 配置声道数、量化位数和取样频率
    45.         wavFile.setnchannels(1)
    46.         wavFile.setsampwidth(2)
    47.         wavFile.setframerate(framerate)

    48.         print 'QTTSAudioGet => ',

    49.         while True:

    50.             pdata = dll.QTTSAudioGet(sessionID, byref(audio_len), byref(synth_status), byref(getret))
    51.             # print 'QTTSAudioGet => audio_len:', audio_len, 'synth_status:', synth_status, 'getret:', getret

    52.             if getret.value != MSP_SUCCESS:
    53.                 print '!MSP_SUCCESS'
    54.                 break

    55.             if pdata:

    56.                 print '>',
    57.                 data = string_at(pdata, audio_len.value)
    58.                 # 将wav_data转换为二进制数据写入文件
    59.                 wavFile.writeframes(data)
    60.             else:
    61.                 print '=',

    62.             if synth_status.value == MSP_TTS_FLAG_DATA_END:
    63.                 print 'MSP_TTS_FLAG_DATA_END'
    64.                 break

    65.             time.sleep(0.1)

    66.         wavFile.close()
    67.         ret = dll.QTTSSessionEnd(sessionID, "Normal")
    68.         print 'QTTSSessionEnd => ret:', ret


    69.     pass


    70. if __name__ == "__main__":
    71.     msp = Msp()

    72.     msp.login()
    73.     msp.tts(text, filename, session_begin_params)
    复制代码



    使用道具 举报 回复
     楼主| RYHAN 发表于 2016-10-28 17:05:55
    8#
    李刚天行健 发表于 2016-9-28 16:53
    我用python调用总是出现10407错误。

    可能和dll版本有关系。 我这边用的是 msc.dll 不是64位的


    使用道具 举报 回复
     楼主| RYHAN 发表于 2016-10-28 17:08:51
    9#
    RYHAN 发表于 2016-10-28 17:02
    生成音频的话,建议用python 的 wave 包
    完整代码如下:

    我还写了个直接输出音频的版本,完整代码如下。
    1. #! /usr/bin/env python
    2. # coding=utf-8

    3. __author__ = 'ryhan'


    4. # 以下代码解决输出乱码问题
    5. import sys
    6. # print sys.getdefaultencoding()
    7. reload(sys)
    8. sys.setdefaultencoding('utf-8')
    9. # print sys.getdefaultencoding()

    10. from ctypes import *
    11. import time
    12. import pyaudio

    13. sys.path.append('.')

    14. dll = windll.LoadLibrary("msc.dll")

    15. uname = "973214924@qq.com"
    16. upass = ""

    17. login_params = "appid = 57d10f01, work_dir = ."
    18. session_params = "voice_name = xiaoyan, text_encoding = utf8, sample_rate = 16000, speed = 50, volume = 50, pitch = 50, rdn = 2"

    19. MSP_SUCCESS = 0
    20. MSP_TTS_FLAG_STILL_HAVE_DATA = 1
    21. MSP_TTS_FLAG_DATA_END = 2
    22. MSP_TTS_FLAG_CMD_CANCELED = 4

    23. text = "亲爱的用户,您好,这是一个语音合成示例,感谢您对科大讯飞语音技术的支持!科大讯飞是亚太地区最大的语音上市公司,股票代码:002230"
    24. print 'text:', text


    25. class Msp:
    26.     def __init__(self):
    27.         pass

    28.     def login(self):
    29.         ret = dll.MSPLogin(uname, upass, login_params)
    30.         print('MSPLogin =>'), ret

    31.     def login_out(self):
    32.         ret = dll.MSPLogout()
    33.         print('MSPLogout =>'), ret


    34.     def tts(self, text):
    35.         ret = c_int()
    36.         sessionID = dll.QTTSSessionBegin(session_params, byref(ret))
    37.         print 'QTTSSessionBegin => sessionID:', sessionID, 'ret:', ret.value

    38.         ret = dll.QTTSTextPut(sessionID, text, len(text), None)
    39.         print 'QTTSTextPut => ret:', ret

    40.         audio_len = c_int()
    41.         synth_status = c_int()
    42.         getret = c_int()

    43.         p = pyaudio.PyAudio()
    44.         stream = p.open(format=p.get_format_from_width(2), channels=1, rate=16000, output=True)

    45.         print 'QTTSAudioGet => ',

    46.         while True:


    47.             pdata = dll.QTTSAudioGet(sessionID, byref(audio_len), byref(synth_status), byref(getret))
    48.             # print 'QTTSAudioGet => audio_len:', audio_len, 'synth_status:', synth_status, 'getret:', getret

    49.             if getret.value != MSP_SUCCESS:
    50.                 print '!MSP_SUCCESS'
    51.                 break

    52.             if pdata:
    53.                 print '>',
    54.                 data = string_at(pdata, audio_len.value)
    55.                 stream.write(data)  # 播放获得到的音频
    56.             else:
    57.                 print '=',

    58.             if synth_status.value == MSP_TTS_FLAG_DATA_END:
    59.                 print 'MSP_TTS_FLAG_DATA_END'
    60.                 break

    61.             time.sleep(0.1)

    62.         ret = dll.QTTSSessionEnd(sessionID, "Normal")
    63.         print 'QTTSSessionEnd => ret:', ret


    64. if __name__ == "__main__":
    65.     msp = Msp()

    66.     msp.login()
    67.     msp.tts(text)
    68.     msp.login_out()
    复制代码



    楼内回复

    python3 下输出不了中文呢?  详情 发表于 2017-2-14 17:57
    使用道具 举报 回复
    Reidzhang 发表于 2016-11-29 15:30:21
    10#
    RYHAN 发表于 2016-10-28 17:08
    我还写了个直接输出音频的版本,完整代码如下。

    非常感谢,学习学习。
    使用道具 举报 回复