科大讯飞的ASR和TSS口碑这么好,在PC和Android资源很多,虽然对*nix似乎支持不很到位,不过还是尝试一下,以下为测试内容。先说结果:如果说某度号称比google更懂中文会让人笑落满口牙,那么说科大讯飞更懂中文,应该当之无愧。讯飞主要提供:
1、语音合成
包括在线与离线合成,支持中文、英文、粤语、中英混、粤英混等。可以设定不同音色,包括普通话女童、普通话男声、普通话女声、粤语、东北话、河南话、湖南话、四川话等。支持多字符集,包括GB2312、GBK、Big5、Unicode、UTF-8等。
2、语音识别
提供在线与离线两种,功能包括前端预处理:端点检测、噪音消除、智能打断,后端识别:连续语音识别、个性化语音识别、置信度输出、多识别结果、多槽识别等。
3、语义理解
能处理基于文法规则的实际业务,支持用户通过自然语言向机器发出某种业务需求,如打电话、发短信、查天气、查股票、查航班、订酒店等。具备基于相似问句语义距离度量的智能知识问答。具备基于本体库自动构建及推理的智能问答。这块画蛇添足。
1、注册
1、到讯飞云去注册帐号,关联手机关联威信,建App,获ID,下载zip。
$ wget xunfei.tar.bz2
$ tar xvf xunfei.tar.bz2
2、头文件
在下载下来的include文件夹下,有五个文件:msp_errors.h、msp_types.h、msp_cmn.h、qisr.h、qtts.h,前两个是通用数据结构,qisr.h是语音识别头文件,qtts.h是语音合成头文件,在开发代码中include即可。
3、库文件
bin文件夹比较多,主要的是libmsc.so和libspeex.so两个库,复制到/usr/lib或/usr/bin目录即可。
$ sudo cp ./libmsc.so /usr/lib
4、make
$ cd samples/asr_sample
$ ./32bit_make.sh
5、可以测试
$ cd bin
$ ./asr_sample

1、建立项目目录
$ mkdir prj1
2、将SDK/Linux_SDK的src和bin和include和libs都拷贝到prj1目录下
$ cp …
3、在src下建源文件
$ cd src/
$ vi main.c
参考samples代码编辑自己源文件。
4、在prj1目录下创建Makefile文件:
DIR_INC = ./include
DIR_BIN = ./bin
DIR_LIB = ./libs
TARGET = prj1
BIN_TARGET = $(DIR_BIN)/$(TARGET)
CROSS_COMPILE =
CFLAGS = -g -Wall -I$(DIR_INC)
ifdef LINUX64
LDFLAGS := -L$(DIR_LIB)/x64
else
LDFLAGS := -L$(DIR_LIB)/x86
endif
LDFLAGS += -lmsc -lrt -ldl -lpthread
OBJECTS := $(patsubst %.c,%.o,$(wildcard *.c))
$(BIN_TARGET) : $(OBJECTS)
$(CROSS_COMPILE)gcc $(CFLAGS) $^ -o $@ $(LDFLAGS)
%.o : %.c
$(CROSS_COMPILE)gcc -c $(CFLAGS) $< -o $@
clean:
@rm -f *.o $(BIN_TARGET)
.PHONY:clean
5、指定库位置
复制SDK/Linux_SDK/samples目录下“32bit_make.sh”或“64bit_make.sh”文件到prj1目录下。
修改libmsc.so库搜索路径
$ make clean;make
$ export LD_LIBRARY_PATH=$(pwd)/libs/x86/
6、source
$ cd prj1/
$ source 32bit_make.sh
7、run
$ cd bin/
$ ./main
8、日志文件位于bin/msc
1、wav
wav格式是目前Windows最直接保存声音数据的文件格式,在涉及声音信号处理时大多是对WAV文件直接操作。
2、riff
在Windows环境下大部分多媒体文件都依循着一种特定结构来存放信息,这称为资源互换文件格式(Resources Interchange File Format),称为RIFF,比如声音的WAV文件,视频的AVI文件,动画的MMM文件等。
RIFF是一种树状结构,基本组成单位是chunk(块),每个chunk由“辨识码-数据大小-数据”组成,所以一个chunk的长度就是“数据”的大小加8Byte。这是一般情况,因为通常chunk本身不会内部再包含chunk,除了极少的例外。RIFF相当于一个根目录,而格式辨识码则相当于具体的盘符如C:、D:。
3、文件头
扩展名为.wav的音频文件是一种非常简单的RIFF文件,其格式辨识码为”WAVE”,整个wav文件包括文件头和数据块两部分,文件头一般会有两种格式。
3.1、标准44字节文件头

3.1.1、RIFF WAVE Chunk:
以’RIFF’作为标示;然后紧跟着为size字段,该size是整个wav文件大小减去ID和Size所占用的字节数,即size:=FileLen-8;再然后是Type字段,为’WAVE’,表示是wav文件。结构定义如下:
struct RIFF_HEADER
{
char szRiffID[4]; // ‘R’,’I’,’F’,’F’
DWORD dwRiffSize;
char szRiffFormat[4]; // ‘W’,’A’,’V’,’E’
};Format Chunk
3.1.2、Format Chunk
以’fmt ‘作为标示。一般情况下Size为16,此时最后附加信息没有;如果为18则最后多了2个字节的附加信息。结构定义如下:
struct WAVE_FORMAT
{
WORD wFormatTag;
WORD wChannels;
DWORD dwSamplesPerSec;
DWORD dwAvgBytesPerSec;
WORD wBlockAlign;
WORD wBitsPerSample;
};
struct FMT_BLOCK
{
char szFmtID[4]; // ‘f’,’m’,’t’,’ ‘
DWORD dwFmtSize;
WAVE_FORMAT wavFormat;
};
3.2、58字节的文件头
这不是Windows的标准WAV文件,而是经过了一些软件处理的。
它比44字节的多了一个fact子块,储存了关于WAV文件内容的重要信息。用不到,暂时不看。
4、数据
data块装的是真正的声音数据,除非安装其它特殊软件否则Windows仅提供WAVE_FORMAT_PCM一种数据格式,即脉冲编码调制PCM:Pulse Code Modulation,其数据存放形式如下图所示,根据声道数不同及取样位数的不同,安排4位的位置。

Data Chunk头结构定义如下:
struct DATA_BLOCK
{
char szDataID[4]; // ‘d’,’a’,’t’,’a’
DWORD dwDataSize;
};
Windows将16位值取值范围定为[-32768,32767],所以0并不一定代表无声,要注意声音格式是l6位还是8位。解压缩后得到的文件仅仅是裸数据,如果不能正常播放声音,可以按照标准的44字节格式,在解码数据前编写一个正确的文件头,使其成为一个有效文件。
5、例如一个真正的wave文件

6、继续说明
Wav全称是Wave,说明就是将音频文件的波形完整记录,要记录波形需要两个最基本参数:
6.1、采样率,以怎样的频率记录波形的变化,常见的WAVE主要有两种,分别对应于单声道的11.025KHz采样率和8Bit采样深度以及双声道的44.1KHz采样率和16Bit的采样值深度。单声道音频文件采样数据为八位的短整数(short int 00H-FFH),双声道立体声声音文件采样数据为16位的整数(int),高八位和低八位分别代表左右两个声道。所有CD一律采用44.1KHz,而DVD/BD视频音轨一律采用48KHz,原则上更高的采样率更为精准,但是一般认为44.1KHz就接近人耳极限。
6.2、采样深度,用多少字节的储存量来储存音频波形,一般采用的是16bit,及更高的24bit,再高的深度意义不大。这样就不难回答为什么常见WAV文件比特率是1141KBit/s了,44.1KHz * 32bit =1141.2。
6.3、还要注意不同采样频率最好整倍数切换。例如下图曲线一是原始采样音频,一共四段五点;如果像曲线二采样率增加一倍,即八段九点,基本无差异;如果采样率为1.5倍,即波形三的6段7点,则新采样波形四就不可接受了。

6.4、音频压缩
音频编码压缩分为有损无损两种,前者例如MP3波形发生了改变,后者例如FLAC其波形和源文件毫无差异。有损效率高,MP3常见比特率在200KBit/s只是WAV的1/6。
按照riff格式讯飞定义的文件头结构:
typedef struct _wave_pcm_hdr
{
char riff[4]; // = “RIFF”
int size_8; // = FileSize – 8
char wave[4]; // = “WAVE”
char fmt[4]; // = “fmt ”
int fmt_size; // = 下一个结构体的大小:16 | 18
short int format_tag; // = PCM : 1
short int channels; // = 通道数 : 1
int samples_per_sec; // = 采样率 : 8000 | 6000 | 11025 | 16000
int avg_bytes_per_sec; // = 每秒字节数 : samples_per_sec * bits_per_sample / 8
short int block_align; // = 每采样点字节数 : wBitsPerSample / 8
short int bits_per_sample; // = 量化比特数: 8 | 16
char data[4]; // = “data”;
int data_size; // = 纯数据长度 : FileSize – 44
} wave_pcm_hdr;
默认文件头是这样:
wave_pcm_hdr default_wav_hdr =
{
{ ‘R’, ‘I’, ‘F’, ‘F’ },
0,
{‘W’, ‘A’, ‘V’, ‘E’},
{‘f’, ‘m’, ‘t’, ‘ ‘},
16,
1,
1,
16000,
32000,
2,
16,
{‘d’, ‘a’, ‘t’, ‘a’},
0
};
音频合成主要代码:
int text_to_speech(const char* src_text, const char* des_path, const char* params)
{
int ret = -1;
FILE* fp = NULL;
const char* sessionID = NULL;
unsigned int audio_len = 0;
wave_pcm_hdr wav_hdr = default_wav_hdr; //默认文件头
int synth_status = MSP_TTS_FLAG_STILL_HAVE_DATA; //状态机模型
if (NULL == src_text || NULL == des_path) …
fp = fopen(des_path, “wb”); …
//一、pre-合成
sessionID = QTTSSessionBegin(params, &ret); //(1)获得本次sessionID
if (MSP_SUCCESS != ret) …
ret = QTTSTextPut(sessionID, src_text, (unsigned int)strlen(src_text), NULL); //(2)put代合成的文本
if (MSP_SUCCESS != ret) …
//二、合成
fwrite(&wav_hdr, sizeof(wav_hdr) ,1, fp); //(3)添加文件头header
while (1)
{
//获取合成音频
const void* data = QTTSAudioGet(sessionID, &audio_len, &synth_status, &ret);
if (MSP_SUCCESS != ret) …
if (NULL != data)
{
fwrite(data, audio_len, 1, fp); //(4.1)添加音频数据
wav_hdr.data_size += audio_len; //(4.2)刷新大小
}
if (MSP_TTS_FLAG_DATA_END == synth_status) break; //出口
usleep(150*1000); //防止频繁占用CPU
}
if (MSP_SUCCESS != ret) …
//修正wav文件头
wav_hdr.size_8 += wav_hdr.data_size + (sizeof(wav_hdr) – 8); //刷新大小
//将修正过的数据写回文件头部,音频文件为wav格式
fseek(fp, 4, 0);
fwrite(&wav_hdr.size_8,sizeof(wav_hdr.size_8), 1, fp); //写入size_8的值
fseek(fp, 40, 0); //将文件指针偏移到存储data_size值的位置
fwrite(&wav_hdr.data_size,sizeof(wav_hdr.data_size), 1, fp); //写入data_size的值
fclose(fp);
fp = NULL;
//三、post-合成
ret = QTTSSessionEnd(sessionID, “Normal”);
if (MSP_SUCCESS != ret) …
return ret;
}
主程序:《iFlytek MSC Reference Manual》
int main(int argc, char* argv[])
{
int ret = MSP_SUCCESS;
const char* login_params = “appid = 5786f5??, work_dir = .”; //登录参数,appid与msc库绑定,勿随意改动
/*
* voice_name: 合成发音人,0:数值优先,1:完全数值,2:完全字符串,3:字符串优先。
* sample_rate: 合成音频采样率
* speed: 合成音频对应的语速
* volume: 合成音频的音量
* pitch: 合成音频的音调
* rdn: 合成音频数字发音方式
* text_encoding: 合成文本编码格式
*/
const char* session_begin_params = “voice_name = xiaoyan, text_encoding = UTF8, sample_rate = 16000, speed = 50, volume = 50, pitch = 50, rdn
= 2”;
const char* filename = “tts_sample.wav”; //合成的语音文件名称
const char* text = “语音合成示例,”; //合成文本
//一、登录
ret = MSPLogin(NULL, NULL, login_params);//第一个参数是用户名,第二个参数是密码,第三个参数是登录参数
if (MSP_SUCCESS != ret) …
//二、合成
ret = text_to_speech(text, filename, session_begin_params);
if (MSP_SUCCESS != ret) …
//三、退出
MSPLogout();
return 0;
}
主要是倒腾这几个函数:
const char *MSPAPI QTTSSessionBegin (const char *params, int *errorCode)
int MSPAPI QTTSTextPut (const char *sessionID, const char *textString, unsigned int textLen, const char *params)
const void *MSPAPI QTTSAudioGet (const char *sessionID, unsigned int *audioLen, int *synthStatus, int *errorCode)
int MSPAPI QTTSGetParam (const char *sessionID, const char *paramName, char *paramValue, unsigned int *valueLen)
int MSPAPI QTTSSessionEnd (const char *sessionID, const char *hints)
主要参数是下面这些:
voice_name,发音人。如男声、女声、童声等。参考《发音人》列表。
speed,合成音频语速。0-100之间的整数,数值越大语速越快。默认为50
volume,合成音频音量。0-100之间的整数,数值越大音量越大。默认为50
pitch,合成音频音调。0-100之间的整数,数值越大音调越高。默认为50
text_encoding,合成文本编码。GB2312;GBK;BIG5;UNICODE;GB18030;UTF8
background_sound,成音频中的背景音。0:无背景音乐 1:有背景音乐。默认为0
aue,音频编码格式和压缩等级。编码算法:raw;speex;speex-wb;编码等级:raw:无等级。speex系列:0-10;默认为speex-wb;7。speex对应sample_rate=8000
speex-wb对应sample_rate=16000。
sample_rate,合成音频格式。8000 16000,默认为16000
ttp,合成文本类型。text: 普通格式文本;ssml:ssml格式文本。默认为text
rdn,合成音频数字发音。0:数值优先,1:完全数值,2:完全字符串,3:字符串优先。默认为0
《发音人》列表:
xiaoyan 普通话 青年女声;yufeng 普通话 青年男声;唐老鸭 donaldduck 普通话 卡通;许小宝 baybyxu 普通话 童声;楠楠 nannan 普通话 童声;
晓倩 xiaoqian 东北话 青年女声;晓蓉 xiaorong 四川话 青年女声;小强 xiaoqiang 湖南话 青年男声;晓美 xiaomei 粤语 青年女声;等。
要么上传语法文件,要么上传用户词表:
int upload_userwords()
{
char* userwords = NULL;
unsigned int len = 0;
unsigned int read_len = 0;
FILE* fp = NULL;
int ret = -1;
fp = fopen(“userwords.txt”, “rb”); …
fseek(fp, 0, SEEK_END);
len = ftell(fp); //获取音频文件大小
fseek(fp, 0, SEEK_SET);
userwords = (char*)malloc(len + 1);
if (NULL == userwords) …
read_len = fread((void*)userwords, 1, len, fp); //读取用户词表内容
if (read_len != len) …
userwords[len] = ‘�’;
MSPUploadData(“userwords”, userwords, len, “sub = uup, dtt = userword”, &ret); //上传用户词表
if (MSP_SUCCESS != ret) …
return ret;
}
核心的听写代码
void run_iat(const char* audio_file, const char* session_begin_params)
{
const char* session_id = NULL;
char rec_result[BUFFER_SIZE] = {NULL};
char hints[HINTS_SIZE] = {NULL}; //hints为结束本次会话的原因描述,由用户自定义
unsigned int total_len = 0;
int aud_stat = MSP_AUDIO_SAMPLE_CONTINUE ; //音频状态
int ep_stat = MSP_EP_LOOKING_FOR_SPEECH; //端点检测
int rec_stat = MSP_REC_STATUS_SUCCESS ; //识别状态
int errcode = MSP_SUCCESS ;
FILE* f_pcm = NULL;
char* p_pcm = NULL;
long pcm_count = 0;
long pcm_size = 0;
long read_size = 0;
if (NULL == audio_file) …
f_pcm = fopen(audio_file, “rb”);
if (NULL == f_pcm) …
fseek(f_pcm, 0, SEEK_END);
pcm_size = ftell(f_pcm); //获取音频文件大小
fseek(f_pcm, 0, SEEK_SET);
p_pcm = (char *)malloc(pcm_size);
if (NULL == p_pcm) …
read_size = fread((void *)p_pcm, 1, pcm_size, f_pcm); //读取音频文件内容
if (read_size != pcm_size) …
printf(“n开始语音听写 …n”);
session_id = QISRSessionBegin(NULL, session_begin_params, &errcode); //听写不需要语法,第一个参数为NULL
if (MSP_SUCCESS != errcode) …
while (1)
{
unsigned int len = 10 * FRAME_LEN; //每次写入10帧*20ms=200ms音频。16k采样率,16位音频,每帧音频20ms、大小640Byte
int ret = 0;
if (pcm_size < 2 * len) len = pcm_size;
if (len <= 0) break; //出口,识别尾部
aud_stat = MSP_AUDIO_SAMPLE_CONTINUE;
if (0 == pcm_count) aud_stat = MSP_AUDIO_SAMPLE_FIRST;
printf(“>”);
ret = QISRAudioWrite(session_id, (const void *)&p_pcm[pcm_count], len, aud_stat, &ep_stat, &rec_stat);
if (MSP_SUCCESS != ret) …
pcm_count += (long)len;
pcm_size -= (long)len;
if (MSP_REC_STATUS_SUCCESS == rec_stat) //已经有部分听写结果
{
const char *rslt = QISRGetResult(session_id, &rec_stat, 0, &errcode);
if (MSP_SUCCESS != errcode) …
if (NULL != rslt)
{
unsigned int rslt_len = strlen(rslt);
total_len += rslt_len;
if (total_len >= BUFFER_SIZE) …
strncat(rec_result, rslt, rslt_len);
}
}
if (MSP_EP_AFTER_SPEECH == ep_stat) break;//出口,到达静音
usleep(200*1000); //模拟人说话时间间隙。200ms对应10帧的音频
}
errcode = QISRAudioWrite(session_id, NULL, 0, MSP_AUDIO_SAMPLE_LAST, &ep_stat, &rec_stat);
if (MSP_SUCCESS != errcode) …
while (MSP_REC_STATUS_COMPLETE != rec_stat)
{
const char *rslt = QISRGetResult(session_id, &rec_stat, 0, &errcode);
if (MSP_SUCCESS != errcode) …
if (NULL != rslt)
{
unsigned int rslt_len = strlen(rslt);
total_len += rslt_len;
if (total_len >= BUFFER_SIZE) …
strncat(rec_result, rslt, rslt_len);
}
usleep(150*1000); //防止频繁占用CPU
}
printf(“n语音听写结束n”);
printf(“%sn”,rec_result);
printf(“=============================================================n”);
QISRSessionEnd(session_id, hints);
}
主程序:
int main(int argc, char* argv[])
{
int ret = MSP_SUCCESS;
int upload_on = 1; //是否上传用户词表
const char* login_params = “appid = 5786f5??, work_dir = .”; // 登录参数,appid与msc库绑定勿改
const char* session_begin_params = “sub = iat, domain = iat, language = zh_ch, accent = mandarin, sample_rate = 16000,
result_type = plain, result_encoding = utf8”;
/* 用户登录 */
ret = MSPLogin(NULL, NULL, login_params); //第一个用户名,第二个密码,第三个登录参数
if (MSP_SUCCESS != ret) …
printf(“演示示例选择:是否上传用户词表?n0:不使用n1:使用n”);
scanf(“%d”, &upload_on);
if (upload_on)
ret = upload_userwords();
run_iat(“wav/iflytek02.wav”, session_begin_params);
exit:
MSPLogout(); //退出登录
return 0;
}
为了测试,需要录音,用Sox。Sox是Lance Norskog创立的最著名的声音文件格式转换工具,跨平台,支持常见格式,能够进行声音滤波、采样频率转换等。Sox附带有rec,play两个程序,rec是用来录音的,play是用来播放的。
Sox的语法格式如下所示:
sox 全局参数 格式化参数 输入文件1 格式化参数 输入文件2 … 格式化参数 输出文件 效果器全局参数在最前面。每个输入文件都有相应的格式化参数,可以有多个输入文件,在每一个输出文件前面再加上格式化参数,最后是效果器。
1、一个简单的命令:
$ sox file1.wav -v 0.6 file2.wav
-v是调整音量的选项,是一种线性调整,0.6并不是调整到原先的0.6,而是幅值调整,如果-v后面的数字比1大,则增加音量,反之则减少音量,如果是负数那么在调整的同时还对音频进行反相变换,但也不是可以任意增加的,取值太大容易产生削波现象。
2、要取什么值好呢:
$ sox file1.wav -n stat -v
$ 1.003
这就是不失真最大调整量了。
作用是对音频文件做一个统计分析,并将结果打印到标准错误文件。参数方面,-n表示输出文件为空。stat为效果器,-v表示将要打印跟音量调整有关内容。
3、查看文件信息
$ sox 01.wav -n stat
4、提取
提取开头的10秒
$ sox 01.wav 011.wav trim 0 10
提取10-277秒的音频
$ sox 01.wav 012.wav trim 10 227
5、调整
调整采样率为48000:
$ sox file1.wav -r 48000 file2.wav
6、转换
wav转mp3
$ sox 01.wav sox 01.mp3
7、单声道转立体声:
$ sox file1.wav -c 2 file2.wav
其中-c就是声道转换选项,-c 2可写成-c2,所以-c1表示单声道,-c4表示4声道。
8、组合
打印细节,音量调整,采样率调整,声道转换,等等都结合起来:
$ sox -V4 -v 1.2 file1.wav -r 48000 -c 2 file2.wav
其中-V4表示打印最多细节。
9、效果器
样本用的是一小段自录声音(3.15分钟长,’wav’格式,44.1 kHz采样速率,16bit单声道)。
10、混合
$ play 01.wav mixer 0.3,0.5,0.8,0.6
采用了mixer效果器,它通过混合或者减少音轨从而减少音轨数,或者通过复制音轨而增加音轨数。
11、节拍器
$ play 01.wav tempo -q 0.8 82 20 16
下面例子则应用了tempo(节拍)效果器:
0.8设置新节拍相对于老节拍的比率,82设置所选算法要划分音频的片段大小,单位毫秒,20是音频长度,依靠它来搜索以寻找重叠点,16是重叠长度。
12颤动器
$ play 01.wav tremolo 3.5 60
3.5是颤音频率,,单位是赫兹Hz,60是深度百分比,具体来说就是”颤”到多长或深。
13、淡入淡出
$ play 01.wav fade t 00:00:100.09
上面例子中,fade是效果器名字,t是声波包络线形式,t是线性斜坡,选q则意味着是正弦波的四分之一,h表示正弦波一半,l为对数,p为倒置抛物线。默认是线性斜坡。00:00:100.09是以hh:mm:ss.fraq形式表示的时间,也可用采样数来算,如设为8000s则为8000个样本。
$ play 01.wav fade t 00:00:50.09 00:01:00 00:00:06
上面是淡入效果,那么要设置淡出效果。上例中t上面已讲,00:00:50.09是从0开始算起,到淡入结束所花费的时间;00:01:00是开始淡出的时间点,00:00:06是开始淡出到结束所花费的时间。也就是说,从00:01:00开始淡出,花费6秒即00:00:06的时间就结束了。上面的时间都可以选择以样本数量为单位,如上所述。
14、回响
自然界中,回声处处可见,比如站在高山上,向周围的山喊话,就会引起回声,在喊和回声之间的时间间隔就是延迟,它的响度就是衰减值,下面给出一个回响例子:
$ play file.xxx echo 0.8 0.88 60 0.4
上式听起来就象用两个乐器演奏同一个样本一样,0.8是输入音量,0.88是输出音量,60是延迟,单位是毫秒,0.4是相对于输入音量的衰减值。
如果延迟时间变长,听起来更象在山顶上的露天演唱会:
$ play file.wav echo 0.8 0.88 1000 0.4
衰减值最好不要大于0.5,否则可能引起输出饱和。
假如延迟很短,听起来象(金属的)机器人的表演。
$ play file.wav 0.8 0.88 6 0.4
想要更多回响也可以实现:
$ play file.wav echo 0.8 0.9 1000 0.3 1800 0.25
如果是站在群山之间,还可能会引起连续回响,即回响本身有碰到邻近山峰,反弹回来,又弹回去,这种效果就是回声,它是连续回响的意思,如果是单独应用一次回声,效果和回响是一样的,下面看一个两次回声例子:
$ play file.wav echos 0.8 0.7 700 0.25 700 0.3
在上式中,echos就是回声效果器,应用这个效果器,回响将被弹回来两次,因为两次延迟时间相同,都是700,这种回响叫对称回声,来一个不对称的回声:
$ play file.xxx echos 0.8 0.7 700 0.25 900 0.3
下面这个例子听起来就象在汽车里演奏一样:
$ play file.wav echos 0.8 0.7 40 0.25 63 0.3
上式由于延迟时间短,听起来感觉有点沉闷,不是吗?
15、rec
Sox附带的程序有rec,play两个程序,rec是用来录音的,play是用来试听效果的,它们语法跟sox是类似的,只是rec时候输入源就变成了内部或外部的设备。常规的,一般录wav用sox就ok,录制mp3可选用mpegrec。
最简单的指定文件名即可录音:
$ rec file.wav
带参数录音:
$ rec -r 16000 -b 16 -c 1 666.wav
以上符合讯飞要求:采样率16K或8KHz,采样位是16位,单声道,格式PCM或WAV。
主要参数:
-r 16000, -r指定采样速率,这里为16K
-b 16,-s指定采样位数,默认-s b为8位,这里-s w为16位。
-c 1,-c指定通道数, 这里-c 1为单通道
-v 12,-v指定音量。
-t mp3,-t指定文件类型,默认wav,这里为mp3
0、设置环境:
$ export PATH=~/XF_U1404401/Linux_voice_1.109/bin:$PATH
1、录制音频:
$ rec -r 16000 -b 16 -c 1 wav/dehaoSpeech.wav
2、识别称文本:
$ iat_sample Y
3、合成另外一种语音:
$ tts_sample –voice_name=xiaomei “我爱北京天安门” dehaoSpeech.wav
4、播放这段语音:
$ play dehaoSpeech.wav
5、还是写个脚本吧:
#!/bin/sh
export PATH=~/XF_U1404401/Linux_voice_1.109/bin:$PATH
rm wav/dehaoSpeech.wav
rec -r 16000 -b 16 -c 1 wav/dehaoSpeech.wav
tts_sample –voice_name=xiaomei `iat_sample Y` dehaoSpeech.wav
play dehaoSpeech.wav
说明:
1、脚本流程就是上面的手工流程一录、二识、三合、四播:(1)rec录制一段我的语音–>(2)文本识别iat_sample识别出这段语音成文字–>(3)语音合成程序tts_sample把这段文字合成某种方言–>(4)play播放这段方言。
2、对语音合成程序tts_sample添加了一些参数处理:

3、用了参数的最长的这句,“tts_sample”是语音合成 这个程序名,“–voice_name=xiaomei ”是第一个参数说明使用xiaomei这个粤语女声,两边用反颚符号“包围起来的`iat_sample Y`表示这个识别程序的文本结果将作为合成程序tts_sample的第二个参数,“dehaoSpeech.wav”作为第三个参数,指定了位置。