1、选择合适的语音识别处理文件.xml(可从各大官网获取)
也会在文章的末尾附上本人使用的文件
2、在linux上编写voicectl.c文件与编译后的xml文件进行交互
为了是代码更加清晰且模块化,讲所需函数写入了common.c文件中
放入common几个重要的函数模块
//进行tcp通讯套接字配置
int setsockopt(int sockfd, int level, int optname,
const void *optval, socklen_t optlen)
{
int retval = setsockopt(sockfd, level, optname, optval, optlen);
if(retval == -1)
{
perror("setsockopt() error");
}
return retval;
}
int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout)
{
int n = select(nfds, readfds, writefds, exceptfds, timeout);
if(n == -1)
{
perror("select() failed");
exit(0);
}
return n;
}
//初始化套接字的封装函数
int init_sock(const char *ubuntu_ip)
{
struct sockaddr_in sin;
int sockfd = socket(af_inet, sock_stream, 0);
//进行端口复用和协议组,通讯模式的配置
int on = 1;
setsockopt(sockfd, sol_socket, so_reuseaddr, &on, sizeof(1));
//连接到虚拟机中
bzero((char *) &sin, sizeof(sin));
sin.sin_family = af_inet;
inet_pton(af_inet, ubuntu_ip, &sin.sin_addr);
sin.sin_port = htons(def_port);
connect(sockfd, (struct sockaddr *)&sin, sizeof(sin));
printf("connected.\n");
return sockfd;
}
void send_pcm(int sockfd, char *pcmfile)
{
// 打开pcm文件
int fd = open(pcmfile, o_rdonly);
// 取得pcm数据的大小
off_t pcm_size = lseek(fd, 0, seek_end);
lseek(fd, 0, seek_set);
// 读取pcm数据
char *pcm = calloc(1, pcm_size);
read(fd, pcm, pcm_size);
// 将pcm发送给语音识别引擎系统
int m = write(sockfd, pcm, pcm_size);
printf("%d bytes has been write into socket!\n", m);
free(pcm);
}
xmlchar *wait4id(int sockfd)
{
char *xml = calloc(1, xmlsize);
printf("wait4id: 1\n");
// 从ubuntu接收xml结果
int n = read(sockfd, xml, xmlsize);
printf("%d bytes has been recv from ubuntu.\n", n);
// 将xml写入本地文件 xmlfile 中
file *fp = fopen(xmlfile, "w");
if(fp == null)
{
perror("fopen() failed");
exit(0);
}
size_t m = fwrite(xml, 1, n, fp);
if(m != n)
{
perror("fwrite() failed");
exit(0);
}
fflush(fp);
return parse_xml(xmlfile);
}
/********************* xml函数列表 *******************/
xmlchar *__get_cmd_id(xmldocptr doc, xmlnodeptr cur)
{
xmlchar *key, *id;
cur = cur->xmlchildrennode;
while (cur != null)
{
if ((!xmlstrcmp(cur->name, (const xmlchar *)"cmd")))
{
key = xmlnodelistgetstring(doc, cur->xmlchildrennode, 1);
printf("cmd: %s\n", key);
xmlfree(key);
id = xmlgetprop(cur, (const xmlchar *)"id");
printf("id: %s\n", id);
xmlfree(doc);
return id;
}
cur = cur->next;
}
xmlfree(doc);
return null;
}
xmlchar *parse_xml(char *xmlfile)
{
xmldocptr doc;
xmlnodeptr cur1, cur2;
doc = xmlparsefile(xmlfile);
if (doc == null)
{
fprintf(stderr,"document not parsed successfully. \n");
return null;
}
cur1 = xmldocgetrootelement(doc);
if(cur1 == null)
{
fprintf(stderr,"empty document\n");
xmlfreedoc(doc);
return null;
}
if(xmlstrcmp(cur1->name, (const xmlchar *)"nlp"))
{
fprintf(stderr,"document of the wrong type, root node != nlp");
xmlfreedoc(doc);
return null;
}
cur1 = cur1->xmlchildrennode;
while (cur1 != null)
{
if ((!xmlstrcmp(cur1->name, (const xmlchar *)"result")))
{
cur2 = cur1->xmlchildrennode;
while(cur2 != null)
{
if((!xmlstrcmp(cur2->name, (const xmlchar *)"confidence")))
{
xmlchar *key = xmlnodelistgetstring(doc, cur2->xmlchildrennode, 1);
if(atoi((char *)key) < 30)
{
xmlfree(doc);
fprintf(stderr, "sorry, i'm not sure what you say.\n");
return null;
}
}
if((!xmlstrcmp(cur2->name, (const xmlchar *)"object")))
{
return __get_cmd_id(doc, cur2);
}
cur2 = cur2->next;
}
}
cur1 = cur1->next;
}
xmlfreedoc(doc);
return null;
}
void send_data_to_8266(int id_num)
{
int sockfd;
/*客户程序开始建立sockfd描述符*/
if((sockfd = socket(af_inet,sock_dgram,0)) ==-1)
{
printf("socket error\n");
exit(1);
}
struct sockaddr_in r_addr;
bzero(&r_addr,sizeof(struct sockaddr_in)); /*将结构体里数据全部置0*/
r_addr.sin_family = af_inet; /*结构体成员赋初值*/
r_addr.sin_addr.s_addr = inet_addr("127.0.0.1");//广播发送信息到这个网段
r_addr.sin_port = htons(10010); // 端口号
int on=1;
setsockopt(sockfd,sol_socket,so_broadcast,&on,sizeof(on));
//设置socket为可广播模式。
//通过设置不同的命令,发送给xml文件进行判断分析
switch(id_num)
{
case 1:sendto(sockfd,"open windows",strlen("open windows"),0,(struct sockaddr *)&r_addr,sizeof(struct sockaddr_in));
printf("open windows\n");
break;
case 2:sendto(sockfd,"open door",strlen("open door"),0,(struct sockaddr *)&r_addr,sizeof(struct sockaddr_in));
printf("open door\n");
break;
case 3:sendto(sockfd,"open led",strlen("open led"),0,(struct sockaddr *)&r_addr,sizeof(struct sockaddr_in));
printf("open led\n");
break;
case 4:sendto(sockfd,"close windows",strlen("close windows"),0,(struct sockaddr *)&r_addr,sizeof(struct sockaddr_in));
printf("close windows\n");
break;
case 5:sendto(sockfd,"close door",strlen("close door"),0,(struct sockaddr *)&r_addr,sizeof(struct sockaddr_in));
printf("close door\n");
break;
case 6:sendto(sockfd,"close led",strlen("close led"),0,(struct sockaddr *)&r_addr,sizeof(struct sockaddr_in));
printf("close led\n");
break;
default:
break;
}
}
在voicectl.c中调用common.c的函数模块实现与.xml文件的交互
//
//
// copyright(c), 2013-2017, gec tech. co., ltd.
//
// file name: gple/voicectl.c
//
// author: gec
//
// date: 2017-01
//
// description: 获取语音指令,根据指令完成相应动作
//
//
//
#include "common.h"
#include <sys/ioctl.h>
#define test_magic 'x' //定义幻数
#define test_max_nr 2 //定义命令的最大序数
//定义led的魔幻数
#define led1 _io(test_magic, 0)
#define led2 _io(test_magic, 1)
#define led3 _io(test_magic, 2)
#define led4 _io(test_magic, 3)
//#define rec_cmd "./arecord -d4 -c1 -r16000 -traw -fs16_le cmd.pcm"
#define rec_cmd "arecord -d3 -c1 -r16000 -traw -fs16_le cmd.pcm"
#define pcm_file "./cmd.pcm"
/* -d:录音时长(duration)
-c:音轨(channels)
-r:采样频率(rate)
-t:封装格式(type)
-f:量化位数(format) */
int said=0;
void catch(int sig)
{
if(sig == sigpipe)
{
printf("killed by sigpipe\n");
exit(0);
}
}
int main(int argc, char const *argv[]) // ./wav2pcm ubuntu-ip
{
signal(sigpipe, catch);
int id_num=0;
if(argc != 2)
{
printf("usage: %s <ubuntu-ip>\n", argv[0]);
exit(0);
}
int sockfd = init_sock(argv[1]); //tcp
while(1)
{
// 1,调用arecord来录一段音频
printf("please to start rec in 3s...\n");
// 在程序中执行一条命令 “录音的命令”
system(rec_cmd);
// 2,将录制好的pcm音频发送给语音识别引擎
send_pcm(sockfd, pcm_file);
// 3,等待对方回送识别结果(字符串id)
xmlchar *id = wait4id(sockfd);
if(id == null)
{
said = 0;
continue;
}
id_num=atoi((char *)id);
if(id_num == 999)
{
printf("bye-bye!\n");
goto exit;
}
if(id_num == 100 )
{
printf("你好,主人!有什么吩咐\n");
said = 1; //唤醒它
system("madplay ../mp3/我在.mp3"); // 放一个语音文件,mp3文件放入上一级目录
}
if( id_num != 100 )
{
send_data_to_8266(id_num);//处理芯片
printf("id: %d\n",id_num);
//调用linux命令播放mp3文件
if(id_num == 1)
{
system("madplay ../mp3/开窗.mp3");
}
if(id_num == 2)
{
system("madplay ../mp3/开门.mp3");
}
if(id_num == 3)
{
system("madplay ../mp3/开灯.mp3");
}
if(id_num == 4)
{
system("madplay ../mp3/关窗.mp3");
}
if(id_num == 5)
{
system("madplay ../mp3/关门.mp3");
}
if(id_num == 6)
{
system("madplay ../mp3/关灯.mp3");
}
if(id_num == 7)
{
system("madplay ../mp3/天气.mp3");
}
}
}
exit:
close(sockfd);
return 0;
}
3、在linux下运行.xml文件与voicectl.c文件
检验通讯连接是否建立,是否可以对语音文件进行处理,在一切准备就绪后在qt上进行实物的操作
qt界面和运行结果如下
设置了开门,关门,开灯,关灯,开窗关窗的qlable模块
通过按钮或者语音命令实现相关操作
在mainwindow.h文件中加入#include <qudpsocket>头文件确保可以进行通信
因为只需要接受数据所以采用了udp通讯协议,在单纯的接受数据方面使用udp协议比起tcp协议更加高效
附上mainwindow.h的代码
#ifndef mainwindow_h
#define mainwindow_h
#include <qmainwindow>
#include <qudpsocket>
namespace ui {
class mainwindow;
}
class mainwindow : public qmainwindow
{
q_object
public:
explicit mainwindow(qwidget *parent = 0);
~mainwindow();
private slots:
void slotrecv();
void on_btnopenwin_clicked();
void on_btnclosewin_clicked();
void on_btnopendoor_clicked();
void on_btnclosedoor_clicked();
void on_btnopenlight_clicked();
void on_btncloselight_clicked();
private:
ui::mainwindow *ui;
qudpsocket *udp;
};
#endif // mainwindow_h
在mainwindow.cpp中进行通信的链接和函数的实现
废话不多说,上代码
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <qnetworkdatagram>
mainwindow::mainwindow(qwidget *parent) :
qmainwindow(parent),
ui(new ui::mainwindow)
{
ui->setupui(this);
udp = new qudpsocket(this);//创建新的qudpsocket对象
udp->bind(qhostaddress::any,10010);//连接服务器
connect(udp,signal(readyread()),this,slot(slotrecv()));//转到槽函数
}
void mainwindow::slotrecv()
{
qnetworkdatagram datagram ;
while (udp->haspendingdatagrams()) {
datagram = udp->receivedatagram();//接受数据
}
if(datagram.data()=="open windows")
{
on_btnopenwin_clicked();//进行对应的处理
}
else if(datagram.data()=="close windows")
{
on_btnclosewin_clicked();
}
else if(datagram.data()=="open door")
{
on_btnopendoor_clicked();
}
else if(datagram.data()=="close door")
{
on_btnclosedoor_clicked();
}
else if(datagram.data()=="open led")
{
on_btnopenlight_clicked();
}
else if(datagram.data()=="close led")
{
on_btncloselight_clicked();
}
}
mainwindow::~mainwindow()
{
delete ui;
}
void mainwindow::on_btnopenwin_clicked()
{
qpixmap pix(":/pic/开窗.jpg");//接受图片资源
ui->lbwin->setpixmap(pix);//qlabel上显示图片在显示图片
}
void mainwindow::on_btnclosewin_clicked()
{
qpixmap pix(":/pic/关窗.jpg");
ui->lbwin->setpixmap(pix);
}
void mainwindow::on_btnopendoor_clicked()
{
qpixmap pix(":/pic/开门.jpg");
ui->lbdoor->setpixmap(pix);
}
void mainwindow::on_btnclosedoor_clicked()
{
qpixmap pix(":/pic/关门.jpg");
ui->lbdoor->setpixmap(pix);
}
void mainwindow::on_btnopenlight_clicked()
{
qpixmap pix(":/pic/openlight.jpg");
ui->lblight->setpixmap(pix);
}
void mainwindow::on_btncloselight_clicked()
{
qpixmap pix(":/pic/closelight.jpg");
ui->lblight->setpixmap(pix);
}
此上就可以在linux上实现语音识别并且与qt的交互了
发表评论