1. 介绍
Jasper是一款基于树莓派的开源语音控制助理, 使用Python语言开发.
Jasper工作原理主要是设备被动监听麦克风, 当收到唤醒关键字时进入主动监听模式, 此时收到语音指令后进行语音识别, 然后对得到的文本进行语义内容解析并处理, 然后将处理结果通过语音合成并输出给用户.
其中涉及到的技术包括声音的录制和播放; 语音识别(ASR/STT); 语义内容(NLU/NLP); 语音合成(TTS)
2. 音频系统
2.1 硬件
音频系统的硬件设备为声卡, 声卡通过DAC(数模转换)和ADC(模数转换)实现音频的输入和输出.
下面是Linux下查看声卡设备的命令
$ lspci | grep -i audio
00:05.0 Audio device: Intel Corporation 82801FB/FBM/FR/FW/FRW (ICH6 Family) High Definition Audio Controller (rev 01)
2.2 软件
在Linux中音频系统结构如下
在桌面Linux系统中, 音频系统通常包含驱动层、服务层(声音服务器)和应用层.
在嵌入式系统中, 音频系统通过只包含驱动层和应用层.
在Linux下有两套音频驱动系统, 分别是OSS和ALSA.
2.2.1 OSS
OSS(Open Sound System), 是类Unix和POSIX兼容系统上统一的声音架构, 兼容OSS API的应用程序可以方便地进行移植
OSS API 主要提供如下设备文件接口
/dev/mixer: 混音及控制
/dev/dsp: 音频输入输出
现如今大部分Linux系统并不提供OSS驱动, 而使用ALSA, 故在此不详述.
更多信息参考<OSS--跨平台的音频接口简介>
2.2.2 ALSA
ALSA(Advanced Linux Sound Architecture)是OSS的继任者, 目前已经成为Linux下主流音频架构
ALSA包含驱动、函数库以及工具包
alsa-driver: 驱动部分, 集成在内核中, 大多以模块的方式存在
驱动可分为如下三层
- 底层的硬件操控层: 负责实现硬件操纵访问功能, 这也是声卡驱动程序中厂商需实现的主要部分
- 中间层核心层: 由各种功能的音频设备组件构成, 为用户提供一些预定义组件(如PCM、AC97、音序器和控制器等), 另外用户也可以自行定义设备组件
- 声卡对象描述层: 它是声卡硬件的抽象描述, 内核通过这些描述可以得知该声卡硬件的功能、设备组件和操作方法等
驱动程序为用户空间提供了如下抽象接口
/proc/asound: 信息接口
/dev/snd/controlCX: 控制接口
/dev/snd/mixerCXDX: 混音器接口
/dev/snd/pcmCXDX: PCM接口
/dev/snd/midiCXDX: MIDI接口
/dev/snd/seq: 音序器接口
/dev/snd/timer: 定时器接口
alsa-lib: 用户空间函数库, 封装驱动提供的抽象接口, 通过文件libasound.so提供API给应用程序使用
alsa-utils: 实用工具包,通过调用alsa-lib实现播放音频(aplay)、录音(arecord) 等工具
2.2.3 服务层
声音服务器介于ALSA和应用程序之间, 解决了不同应用程序之间独占声卡和混音问题; 当没有声音服务器时, 而已使用dmixer来实现简单的混音.
应用程序调用声音服务器的API来播放声音时, 同时把音频数据送到声音服务器, 声音服务器将一个以上的播放请求混音后, 再发送给底层的声卡驱动(ALSA/OSS), 由ALSA或OSS来驱动声卡播放混音后的数据.
ESD(Enlightened Sound Daemon, or EsounD): 是Gnome桌面环境的的声音服务器, 已被PulseAudio替代.
aRts(Analog Real-Time Synthesizer): 是KDE桌面环境的声音服务器, 已被Phonon替代.
PulseAudio: 新一代声音服务器, 能提供更好的音效, 目前是Gnome桌面的默认声音服务器.
JACK Audio Connection Kit: 专业的声音服务器, 为应用程序之间的音频和MIDI数据提供实时、低延迟的连接.
AudioFlinger: Android上的声音服务器.
2.2.4 其他音频库
除了声音服务器之外, 还有一些常见的音频框架和库
GStreamer: 是用来构建流媒体应用的开源多媒体框架.
Phonon: Qt上跨平台多媒体框架.
PortAudio: 音频I/O库, 提供C和C++接口, 跨平台, 在Linux上支持ALSA、OSS后端.
libsoundio: 轻量级抽象库, 提供C接口, 跨平台, 在Linux上支持JACK、PulseAudio、ALSA后端
RtAudio: 实时音频库, 提供C++接口, 跨平台, 在Linux上支持JACK、PulseAudio、ALSA、OSS后端
更多音频相关内容请参考<Linux音频编程介绍>
2.3 Jasper中的音频处理
2.3.1 基础介绍
Python中音频库众多, 常用的有如下:
Pydub: 一个高级音频接口, 需要ffmpeg或者libav支撑.
sounddevice: PortAudio库的绑定, 并与Numpy兼容的录音以及播放库.
PyAudio: PortAudio库的绑定, 需要PortAudio库支撑, 跨平台.
pyalsaaudio: ALSA API的封装, 需要ALSA库支撑, 只支持Linux.
pymad: 使用MAD(MPEG Audio Decoder)库的高级音频接口, 需要libmad支撑.
2.3.2 音频输入
Jasper的音频输入使用的库为PyAudio, 通过PyAudio录制声音并保存为wav格式文件, 然后送给STT引擎处理.
2.3.3 音频输出
Jasper中音频输出主要是将TTS结果输出给用户, 主要有三种
- 使用eSpeak、Festival等离线引擎则直接与系统交互.
- 调用系统的aplay、play命令直接播放Web API返回的音频文件.
- 使用Python库播放Web API返回的音频文件, 使用pymad进行播放.
注意: Jasper在运行中会输出如下信息, 这不是错误.
ALSA lib pcm_dmix.c:1090:(snd_pcm_dmix_open) unable to open slave
ALSA lib pcm.c:2501:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.rear
ALSA lib pcm.c:2501:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.center_lfe
ALSA lib pcm.c:2501:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.side
ALSA lib pcm_route.c:867:(find_matching_chmap) Found no matching channel map
ALSA lib pcm_oss.c:397:(_snd_pcm_oss_open) Cannot open device /dev/dsp
ALSA lib pcm_oss.c:397:(_snd_pcm_oss_open) Cannot open device /dev/dsp
ALSA lib pcm_dmix.c:1090:(snd_pcm_dmix_open) unable to open slave
Cannot connect to server socket err = No such file or directory
Cannot connect to server request channel
jack server is not running or cannot be started
3. 语音识别
语音识别(Speech recognition)技术, 被称为自动语音识别, ASR(Automatic Speech Recognition);
也称语音转文字, Speech To Text(STT), 目前有如下方案
开源方案包括
- CMUSphinx、ISIP、Julius、Kaldi、Mozilla DeepSpeech
专有方案包括
- HTK、RWTH ASR
- Google STT、Amazon Alexa、Microsoft Speech API、Nuance Voice Platform
- Baidu STT、Ali STT、iFlyTek STT
- 基于CMUSphinx有Platypus, FreeSpeech, Vedics, NatI, Simon, Xvoice, Zanzibar, OpenIVR, Dragon Naturally Speaking等方案
- Microsoft Speech API只能在Windows平台上使用, 支持中文
- iFlyTek另有AiSound(语音合成)、AiTalk(语音识别)用于汽车导航的离线引擎
- IBM Watson平台提供了TTS、STT等服务
- Tizen OS也拥有的TTS和STT功能
另外值得一提工具有:
VoxForge: 一个免费的语音语料库和开源语音识别引擎的声学模型库, 支持的引擎包括CMUSphinx、ISIP、HTK和Julius
Python SpeechRecognition: 支持多个引擎和API(包括在线和离线)用于执行语音识别的Python库
4. 语音合成
语音合成即TTS(Text To Speech), 目前有如下方案
开源方案包括
- eSpeak/eSpeakNG、Ekho、Festival/FestVox/Flite、Tizen TTS、MaryTTS(Java)
专有方案包括
- Google TTS、Amazon Polly(IvonaTTS)、Microsoft Speech API、Voice RSS、Neospeech TTS
- Baidu TTS、Ali TTS、iFlyTek TTS
Neospeech TTS提供云端服务和Windows版本, 支持中文
4.1 eSpeak
eSpeak支持中文输出, 不过效果真心不敢恭维
$ espeak -vzh "我是中国人, 我爱中国"
4.2 Ekho
Ekho是一款免费的开源和多语言文本转语音软件
它支持粤语、普通话等等
4.2 Festival
Festival为爱丁堡大学CSTR开发的通用多语言语音合成系统
FestVox为CMU开发的用来构建合成声音的软件
Flite(Festival-Lite)为CMU开发的基于Festival的精简版语音合成系统
简单来说, Festival和Flite可以进行TTS转换, 然后使用FestVox提供的声音进行输出。
// Festival
# yum install festival
$ echo "Hello, You are using festival" | festival –tts
$ festival --tts myfile
// Flite
# yum install flite
$ flite "Hello, You are using flite" a.wav
$ aplay a.wav
Festival效果比espeak稍好, 不过不支持中文
5. 语义内容
这部分的内容是一个非常复杂的东西, 个人理解可以归为自然语言理解(Natural Language Understanding, 简称NLU)或者自然语言处理(Natural Language Processing, 简称NLP)学科范畴.
NLP通常包含如下内容
- 分词: 只针对中文,英文等西方字母语言已经用空格做好分词了, 将文章按词组分开
- 词法分析: 对于英文,有词头、词根、词尾的拆分,名词、动词、形容词、副词、介词的定性,多种词意的选择
- 语法分析: 通过语法树或其他算法,分析主语、谓语、宾语、定语、状语、补语等句子元素
- 语义分析: 通过选择词的正确含义,在正确句法的指导下,将句子的正确含义表达出来。方法主要有语义文法、格文法
Python自然语言处理库很多, 常见的有:
NLTK: Natural Language Toolkit, 自然语言工具箱.
TextBlob: 提供了一个简单的API来处理文本数据, 用于常见的NLP任务.
Gensim: 用于主题建模、文档索引和大型语料库相似性检索.
jieba: 中文分词组件.
SnowNLP: 可以方便的处理中文文本内容.
Jasper解析语义内容目前采用比较简单的方式, 从STT处理后得到用户的命令文本, 判断文本是否包含已注册的模块关键字中, 如包含则由关键字对应模块进行处理.
其中, 部分模块使用semantic库
参考:
<AlexaPi>
<mycroft>
<Python的webrtc库实现语音端点检测>