如何用python写小工具_用python写一个录音小工具

Python的paramiko,wxPython库的应用

Sound eXchange 命令行

需求

最近在给一个做语音识别的项目做QA工作。众所周知,此类人工智能方面的项目都需要一些数据收集的工作。作为一个比较小型的团队,暂时还没有使用外包团队来做大量的数据,前期数据来源都是团队内的同事录音。

我们的录音工具是树莓派+麦克风阵列,通过ssh,可以用电脑操作树莓派开始录音和停止录音。虽然从QA的角度来说,操作非常固定,但是团队同事有近一半同事不是程序猿,看到secureCRT这么恐怖的界面(此处应有图)大多还是有心理障碍。

所以为了提升用户体验(其实是没有工具就得我一个人来录了),用python做了个简单的工具,达到了点点就能用效果。顺带还整合了两三波新的需求

基本功能

可以从语料库中随机出一句话,展示在界面上给朗读人看

可以点击按钮开始录音,点击按钮结束录音。留了一个取消录音功能防止嘴飘。

有一些环境参数(性别,安静环境/嘈杂环境,距离等)可以手动填入

结束录音后可以按照格式保存为xxxx.wav文件

升级功能

支持播放已有语音的功能,用于做环境噪音合成

原理

麦克风阵列通过USB连接到树莓派,树莓派通过无线连接到插在电脑上的360随身wifi上。PC通过secureCRT或者mac的ssh语句可以远程到树莓派上执行指令。

连上以后执行下述命令即可开始录音。

$arecord -D "plughw:1,0" -r 16000 -c 10 -f S16_LE test.wav

录音指令是阻塞的,ctrl+C停止录音。

Version.1 Flask + paramiko

第一个版本就是基于上述原理的。而且因为要做个界面,所以就选了比较熟悉的Bootstrap做网页,Flask做后端,通过paramiko来执行操作。

paramiko

连接

paramiko创建ssh连接的方式如下:

import paramiko

IP = "xxx.xxx.xxx.xxx"

PORT = 22

USERNAME = "user"

PASSWORD = "pwd"

ssh = paramiko.SSHClient()

ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

ssh.connect(IP, PORT, USERNAME, PASSWORD)

执行指令

paramiko中执行指令的类有2个,一个是上述代码中的ssh,可以用stdin, stdout, stderr = ssh.exec_command(cmd)来执行cmd指令,还有一个是可以用channel来执行。

chan = ssh.get_Transport().open_session()

chan = send(cmd)

str = chan.recv(recv_buffer)

考虑到上述录音指令是阻塞的,因此如果采用ssh.exec_command(cmd)没有办法通过ctrl+C来停止录音。因此考虑采用channel.send的方法。ctrl+C可以用channel.send('\x03')来执行。

但是各种花式调用以后,一直都没能停掉录音的进程,原因不明。

因此尝试了一下直接kill掉进程可以保存数据以后,选择了简单粗暴地kill掉arecord所在进程的方法。那么接下来的问题就是获取arecord所在进程id的方法了。

执行$ps -ef | grep \"arecord\" | grep -v grep | awk '{print $2}'可以获取到arecord所在进程pid,再拼接指令$kill -9 xxxx即可杀掉进程。

前端

前端其实没啥好说,提交表单,ajax刷新页面。不过之前其实也没有写过ajax的get方法,所以记录一下

function randomclick(){

$.get("/random", function(data){document.getElementById('scentence').innerHTML = data;})

};

整体框架

解决了上述执行指令的问题以后,基本就是给网页提供接口了。除了随机语句的功能以外,就是

开始录音:执行录音语句

结束录音:结束录音进程,并将语音文件重命名为指定格式的wav文件

取消录音:结束录音进程,删除临时语音文件

Version.2 wxPython+sox

后来因为有了新的需求,主要是播放wav文件和文件命名优化。回过头来看了看,觉得这种需求做成网页其实是不大合适的,毕竟根本没法处理并发的情况。所以决定用python的UI库来做成一个小工具。

之前用过python的pyqt库,但是不知道为什么安装不上pyqt(我觉得就是那阵特别不顺,没别的!),于是换成了wxPython。后来发现wxPython的media还自带音频播放功能。

wxPython

UI设计

大概描述一下需求吧

文本展示框,附带2个功能按钮,只改变该文本框的内容

退出时保存一些运行信息到文件中

几个信息输入框,可能有select,也有可能有文本输入

开始录音、结束录音和取消录音按钮

选择播放录音目录的按钮和播放录音的按钮

接下来就一个一个需求点来说吧

文本展示框

sentence = wx.TextCtrl(self, style = wx.TE_MULTILINE, size = (xx, xx))

sentence.SetValue(str)

str = sentence.GetValue()

style = wx.TE_MULTILINE表示该文本框为多行文本框,会自动换行。默认为单行文本框。可以用SetValue方法设置其值,也可以用GetValue来读取文本框的值。

退出时保存信息

def __init__(self, parent, title)

self.Bind(wx.EVT_CLOSE, self.onExit, parent)

def onExit(self, evt):

# do sth

evt.Skip()

pass

在init函数中通过self.Bind将wx.EVT_CLOSE事件绑定到self.onExit函数上。

在self.onExit函数中将运行时的参数保存于文档中。

注意最后需要evt.Skip()来执行关闭界面的功能

特别需要注意的是,当前类需要继承wx.Frame才能使得关闭界面与当前类的wx.EVT_CLOSE事件绑定。

选择框

category_list = ["男", "女"]

classify = wx.Choice(self, -1, choices=category_list, size = (100, 48))

classify.SetSelection(0)

wx.Choice组件需要提供下拉选择列表,比如category_list,可以用SetSelection(idx)将列表中的idx项设为默认值。如果没有设定默认值,默认显示为空。

目录选择按钮

def onClickSelectDir(self, evt):

dlg = wx.DirDialog(self, "Choose a directory:")

if dlg.ShowModal() == wx.ID_OK:

path = dlg.GetPath()

self.updatelist(path)

dlg.Destroy()

将目录选择按钮的wx.EVT_BUTTON绑定至onClickSelectDir函数上。通过path = dlg.GetPath()获取到选择的目录以后,执行自定义的updatelist(path)来完成保存数据的功能。

播放功能

def __init__(self, parent, title):

try:

self.mc = wx.media.MediaCtrl(self, style=wx.SIMPLE_BORDER)

except NotImplementedError:

self.Destroy()

raise

self.Bind(EVT_BUTTON, onPlay, playbutton)

def onPlay(self, evt):

self.mc.Load(self.filename)

time.sleep(0.5)

self.mc.Play()

在init中定义MediaCtrl控件

把playbutton的点击事件和onPlay函数绑定

onPlay函数中,首先用MediaCtrl组件的Load函数加载媒体文件,sleep(0.5)后执行Play函数。

其实这种写法并不是非常专业,之前调研的结果是需要处理EVT_MEDIA_LOADED事件,但是尝试发现将此事件与函数绑定后并未触发该事件,因此简单粗暴sleep解决。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值