概述

最近在对接百度TTS的python接口,对接的过程中发现一些问题,记录下解决方案。

百度TTS接口返回的音频数据格式有4种,分别是mp3,pcm-16k,pcm-8k,wav(pcm-16k)。

我们需要的结果是wav(pcm-8k)。

需求对齐后,分析解决方案,主要有以下几个选择。

1, mp3转码为wav,比如python库AudioSegment。

2, wav(pcm-16k)重采样为wav(pcm-8k),比如python库wave。

3, pcm-8k转换为wav格式,比如python库wave。

4, pcm-8k手动增加wav格式头信息,写入文件。

今天选择第4种方案,并顺便复习了一下wav格式的头部信息。

环境

python 3.10.3

wav文件格式

先复习一下wav文件的格式信息。

下面的截图是根据我的理解画的,仅仅针对pcm编码格式,其他压缩编码格式会多一个fact chunk(在fmt chunk和data chunk中间),有兴趣的可以自行查找资料。

源码

之前用c写过wav的头文件信息,用python还是第一次。

其中aip是百度tts的python库,struct是python内建模块,用于python字符串和C语言结构体之间的转换,我们用struct库对字符串和整数做序列化。

#required python3

from aip import AipSpeech

from struct import pack

def tts_baidu(content, filename):

#init client

client = AipSpeech(APP_ID, API_KEY, SECRET_KEY)

## aue:3-mp3, 4-pcm-16k, 5-pcm-8k, 6-wav(pcm-16k)

result  = client.synthesis(text = content, lang = 'zh', ctp = 1, options = {'aue': 5, 'per': 0, 'vol': 5})

# 识别正确返回语音二进制 错误则返回dict 参照下面错误码

if not isinstance(result, dict):

with open(filename, 'wb') as f:

##aue use 5-pcm-8k, write wav header info first

header = ''

header = pcm_wav_head(len(result), header)

f.write(header)

f.write(result)

f.close()

else:

raise Exception("tts fail, %s" % str(result))

return

###ONLY for pcm, 8000 sample, 16bits, 1 channel

def pcm_wav_head(data_len, header = ''):

header = b'RIFF' #WAVE DES, 4

header += pack('I', (data_len + 36)) #wav chunk len, 4

header += b'WAVE' # WAVE, 4

header += b'fmt ' #fmt , 4

header += pack('I', 16) #PCM fmt info len, 4

header += pack('H', 1) #fmt type PCM 0x0001, 2

header += pack('H', 1) #1 channel, 2

header += pack('I', 8000) #sample 8000, 4

header += pack('I', int(1 * 8000 * 16 / 8)) #bytes per second, 4

header += pack('H', int(1 * 16 / 8)) #sampling frame size, 2

header += pack('H', 16) #bit depth, 2

header += b'data' #data

header += pack('I', data_len) #data len

return header

if __name__ == "__main__":

content = '123456'

filename = r'C:\Users\12345\Desktop\101.wav'

tts_baidu(content, filename)

测试

发送tts请求,根据返回结果写wav文件,wav文件用UE打开,见截图。

截图中,我们可以看到几个数据段的标识,“RIFF“,”WAVEfmt “,”data“。

总结

简单复习了一下wav格式的头部信息,更加复杂的编解码和压缩格式头部信息也都可以在网上找到详细的描述。

wav是一个封装格式,封包的信息都在wav头中。

pcm编码格式是不压缩的语音编码格式,封装pcm数据的wav文件格式相对简单,对于理解音频文件的打包封装有一定帮助。

空空如常

求真得真

wav文件头信息的更多相关文章

  1. sublime 设置新建文件自动添加author(作者)等文件头信息

    很多时候, sublime 自带自动添加文件头信息, 但是并不是我们想要比如下面这样的:新建一个python文件 自动添加的author 信息== 上面并不是我想要的, 我想要下面这样的效果:== 这 ...

  2. 给pcm格式文件加wav文件头

    #include <stdlib.h>#include <stdio.h>#include <string.h>void main(){ //wav头的结构如下所示 ...

  3. eclipse快速配置spring相关xml文件头信息

    通过spring tools 插件工具来快速配置xml头信息 ctrl +n 创建-----------> 输入spring 选中spring Beann Configuration File ...

  4. FFmpeg命令行工具学习(一):查看媒体文件头信息工具ffprobe

    一.简述 ffprobe是ffmpeg命令行工具中相对简单的,此命令是用来查看媒体文件格式的工具. 二.命令格式 在命令行中输入如下格式的命令: ffprobe [文件名] 三.使用ffprobe查看 ...

  5. Pycharm中.py文件头信息配置

    在社区版的Pycharm开发软件中设置每次新建.py文件都会自动生成如下信息 #! /usr/bin/env python # -*- coding:utf-8 -*- # Author: Tdcqm ...

  6. WAV文件头相关资料

    http://stackoverflow.com/questions/6284651/avaudiorecorder-doesnt-write-out-proper-wav-file-header h ...

  7. DCMTK读取DICOM文件头信息的三种方法

    Howto: Load File Meta-Header Here's an example that shows how to load the File Meta Information Head ...

  8. php通过文件头检测文件类型通用类(zip,rar…)(转)

    在做web应用时候,通过web扩展名判断上存文件类型,这个是我们常使用的.有时候我们这样做还不完善.可能有些人上存一些文件,但是他通过修改 扩展名,让在我们的文件类型之内. 单实际访问时候又不能展示( ...

  9. java通过文件头来判断文件类型

    import java.io.FileInputStream; import java.io.IOException; import java.util.HashMap; import java.ut ...

  10. pycharm新建py文件时,自动补充文件头注释信息

    步骤: 1.File -->Settings 2.选择 File and Code Templates -> Files -> Python Script 文件头注释信息代码样式: ...

随机推荐

  1. 如何将 performance_schema 中的 TIMER 字段转换为日期时间

    问题 最近有好几个朋友问,如何将 performance_schema.events_statements_xxx 中的 TIMER 字段(主要是TIMER_START和TIMER_END)转换为日期 ...

  2. 搭建前端项目时出现了.../dist/index.mjs:128 if (!require.cache) { ^ ReferenceError: require is not defined...

    具体报错如下: 修改node_modules/vite-plugin-mock/dist/index.mjs 加入如下内容 // 解决报错问题 import { createRequire } fro ...

  3. SpringBoot整合简单的定时任务~

    定时任务框架很多种Quartz,SpringTask,xxljob,PowerJob... 1.JDK提供的timer // JDK提供的 Timer timer = new Timer(); //t ...

  4. DRF过滤器

    https://www.django-rest-framework.org/api-guide/filtering 一般情况下,我们可以重写DRF视图类的get_queryset()方法来实现查询结果 ...

  5. ASR项目实战-方案设计

    对于语音识别产品的实施方案,给出简易的业务流程,仅供参考. 如下流程图,可以使用如下两个站点查看. web chart Web Sequence Diagrams 文件转写 创建文件转写任务 客户应用 ...

  6. ElasticSearch之Get index API

    获取指定索引的基本信息. 命令样例如下: curl -X GET "https://localhost:9200/testindex_001?pretty" --cacert $E ...

  7. ElasticSearch之Force merge API

    使用本方法,可以触发强制合并操作. 默认情况下,ElasticSearch会在后台周期性触发合并操作,因此不需要用户刻意使用本方法. 使用强制合并的弊端: 可能会产生大于5G的segment对象,而E ...

  8. 从零玩转Nginx

    01[熟悉]实际开发中的问题? 现在我们一个项目跑在一个tomcat里面 当一个tomcat无法支持高的并发量时.可以使用多个tomcat 那么这多个tomcat如何云分配请求 |-nginx 02[ ...

  9. 记录一次K8s pod被杀的排查过程

    问题描述 今天下午运维反馈说我们这一个pod一天重启了8次,需要排查下原因.一看Kiban日志,jvm没有抛出过任何错误,服务就直接重启了.显然是进程被直接杀了,初步判断是pod达到内存上限被K8s ...

  10. Vue 2 和 Vue 3 中 toRefs的区别

    摘要:本文将介绍 Vue 2 和 Vue 3 中 toRefs 函数的不同用法和行为,并解释其在各个版本中的作用. 正文: Vue 是一款流行的 JavaScript 框架,用于构建用户界面.在 Vu ...