7 Star 52 Fork 13

王揆 / lark-release

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README
Unlicense

logo

English | 简体中文

介绍

百灵鸟 (lark) 是一个免费、轻量、功能强大的软件音频DSP。它提供了一种灵活可扩展的方法来设计效能高、空间占用小、延时低的音频路由,让您可以像搭积木一样构建音频系统。

主要特性

  • 支持实时操作音频路由
    • 实时加载/卸载块
    • 实时改变路径
    • 实时调节块参数
  • 支持预编译的输入/输出块
    • 文件读取(file-reader), 文件写入(file-writer), 流输入(stream-in), 流输出(stream-out), alsa录音, alsa播放, tinyalsa录音, tinyalsa播放, portaudio录音, portaudio播放
  • 支持预编译的算法块
    • 增益(gain), 混音器(mixer), 复制器(duplicator), 多路复用器(multiplexer), 声道交织(interleave), 声道分离(de-interleave), 格式适配器(format-adapter), 延时器(delay), 对齐(align), 缓存(buffer), 淡入(fade-in), 淡出(fade-out)
    • speexdsp算法: 重采样(speex-resampler), 前处理(speex-preprocessor)
    • soundtouch算法: 音调调节器(pitch), 节拍调节器(tempo), 速度调节器(rate)
    • sox效果器: 音量(vol), 镶边(flanger), 颤音(tremolo), 回音(echos), 合唱(chorus), 卡拉OK(oops), 均衡器(equalizer), 高通(highpass), 低通(lowpass), 等等
  • 支持无限客制化块
  • 支持每块最多32个输入端点,32个输出端点
  • 支持基于帧的时间戳和基于采样点的时间戳
  • 支持实时调试工具
    • 打印状态
    • 打印路由快照到文件
    • 实时设定日志等级
    • 转储日志到文件
    • 转储各个块的音频数据到文件
  • 跨平台
    • Linux (x86_64, aarch64, armv7l)
    • MacOS (x86_64)
    • Android (aarch64)

开始吧

百灵鸟 是由一个基础的动态库liblark.so,各种可选的块(动态加载库)例如libblkmixer.so,和一个可选的可执行调试工具lkdb组成。基于 百灵鸟,您可以很容易地创建您想实现的既可以简单又可以复杂的音频路由,实时启动/停止任意一个路由,或者实时设定/获取任意块的参数。

第1步

由于 百灵鸟 依赖于klogging库,您首先需要安装klogging。访问 https://gitee.com/wksuper/klogging 以安装之。另一种方式是,此仓库已经包含了预编译好的libklogging.so,它会随着 百灵鸟 的安装而一起安装。

第2步

安装 百灵鸟 到您的Linux机器。

cd lark-release
sudo ./install.sh
sudo ldconfig

当您不需要 百灵鸟 时,您可以使用sudo ./uninstall.sh来移除它。

第3步

运行音频路由。

例1:运行一个单路由,做立体声音乐文件播放

RouteA

  libblkfilereader.so     libblkalsaplayback.so
  *******************      ******************
  *                 *      *                *
  *  filereader_0   *0--->0* alsaplayback_0 *
  *                 *      *                *
  *******************      ******************
x86_64-linux-gnu/bin/larkexample1

如果没错误的话,音乐文件应该开始播放了。

这个例子的源代码在此:larkexample1.cpp

例2:运行一个单路由,把两个音乐文件输入做带各自增益的混合播放

RouteA

 libblkfilereader.so   libblkdeinterleave.so   libblkgain.so           libblkmixer.so       libblkinterleave.so     libblkpaplayback.so

  *****************     ******************     *************           **************       *******************      ******************
  *               *     *                *0-->0*           *0-------->0*            *0---->0*                 *      *                *
  * filereader_0  *0-->0* deinterleave_0 *1-->1*           *1---+      *   mixer_0  *       *   interleave_0  *0--->0*  paplayback_0  *
  *               *     *                *     *           *    | +-->1*            *   +->1*                 *      *                *
  *****************     ******************     *           *    | |    **************   |   *******************      ******************
                                               *   gain_0  *    | |                     |
  *****************     ******************     *           *    | |    **************   |
  *               *     *                *     *           *    +-|-->0*            *0--+
  * filereader_1  *0-->0* deinterleave_0 *0-->2*           *2-----+    *   mixer_1  *
  *               *     *                *1-->3*           *3-------->1*            *
  *****************     ******************     *************           **************

运行例2之前,需要先安装 PortAudio 库。

sudo apt install libportaudio2

运行例2:

x86_64-linux-gnu/bin/larkexample2

如果没错误的话,两个音乐文件应该开始混合播放输出了。

开启另一个shell,在里面您可以通过lkdb调节他们的音量增益。

$ lkdb status     # 显示百灵鸟状态
RouteA is RUNNING, 319 frames processed OK, 0 error frame
	blkmixer_1
		(I00) <-- lnk_7    48000Hz   S16_LE  1ch    960samples/frame
		(I01) <-- lnk_9    48000Hz   S16_LE  1ch    960samples/frame
		(O00) --> lnk_11   48000Hz   S16_LE  1ch    960samples/frame
	blkdeinterleave_1
		(I01) <-- lnk_3    48000Hz   S16_LE  2ch    960samples/frame
		(O00) --> lnk_4    48000Hz   S16_LE  1ch    960samples/frame
		(O01) --> lnk_5    48000Hz   S16_LE  1ch    960samples/frame
	blkmixer_0
		(I00) <-- lnk_6    48000Hz   S16_LE  1ch    960samples/frame
		(I01) <-- lnk_8    48000Hz   S16_LE  1ch    960samples/frame
		(O00) --> lnk_10   48000Hz   S16_LE  1ch    960samples/frame
	blkinterleave_0
		(I00) <-- lnk_10   48000Hz   S16_LE  1ch    960samples/frame
		(I01) <-- lnk_11   48000Hz   S16_LE  1ch    960samples/frame
		(O00) --> lnk_12   48000Hz   S16_LE  2ch    960samples/frame
	blkfilereader_0
		(O00) --> lnk_0    48000Hz   S16_LE  2ch    960samples/frame
	blkdeinterleave_0
		(I00) <-- lnk_0    48000Hz   S16_LE  2ch    960samples/frame
		(O00) --> lnk_1    48000Hz   S16_LE  1ch    960samples/frame
		(O01) --> lnk_2    48000Hz   S16_LE  1ch    960samples/frame
	blkfilereader_1
		(O00) --> lnk_3    48000Hz   S16_LE  2ch    960samples/frame
	blkgain_0
		(I00) <-- lnk_1    48000Hz   S16_LE  1ch    960samples/frame
		(I01) <-- lnk_2    48000Hz   S16_LE  1ch    960samples/frame
		(I02) <-- lnk_4    48000Hz   S16_LE  1ch    960samples/frame
		(I03) <-- lnk_5    48000Hz   S16_LE  1ch    960samples/frame
		(O00) --> lnk_6    48000Hz   S16_LE  1ch    960samples/frame
		(O01) --> lnk_7    48000Hz   S16_LE  1ch    960samples/frame
		(O02) --> lnk_8    48000Hz   S16_LE  1ch    960samples/frame
		(O03) --> lnk_9    48000Hz   S16_LE  1ch    960samples/frame
	blkpaplayback_0
		(I00) <-- lnk_12   48000Hz   S16_LE  2ch    960samples/frame

No fifo
lkdb setparam RouteA blkgain_0 1 0 0.5    # kanr-48000_16_2.pcm左声道的输出音量变低
lkdb setparam RouteA blkgain_0 1 1 0.5    # kanr-48000_16_2.pcm右声道的输出音量变低
lkdb setparam RouteA blkgain_0 1 0 0.0    # kanr-48000_16_2.pcm左声道的输出静音
lkdb setparam RouteA blkgain_0 1 1 0.0    # kanr-48000_16_2.pcm右声道的输出静音

lkdb setparam RouteA blkgain_0 1 2 0.5    # pacificrim-48000_16_2.pcm左声道的输出音量变低
lkdb setparam RouteA blkgain_0 1 3 0.5    # pacificrim-48000_16_2.pcm右声道的输出音量变低
lkdb setparam RouteA blkgain_0 1 2 0.0    # pacificrim-48000_16_2.pcm左声道的输出静音
lkdb setparam RouteA blkgain_0 1 3 0.0    # pacificrim-48000_16_2.pcm右声道的输出静音

lkdb setparam RouteA blkgain_0 1 0 1.0    # kanr-48000_16_2.pcm左声道的输出音量恢复
lkdb setparam RouteA blkgain_0 1 1 1.0    # kanr-48000_16_2.pcm右声道的输出音量恢复

lkdb setparam RouteA blkgain_0 1 2 1.0    # pacificrim-48000_16_2.pcm左声道的输出音量恢复
lkdb setparam RouteA blkgain_0 1 3 1.0    # pacificrim-48000_16_2.pcm右声道的输出音量恢复

这个例子的源代码在此:larkexample2.cpp

例3:运行双路由,一个做音乐播放,一个采集麦克风以做关键词侦测

                                                                                                     ****************      ******************      ***************
                                                                                        RouteA       *              *      *                *      *             *
                                                                                                     * filereader_0 *0--->0* alsaplayback_0 *0--->0* streamout_0 *
                                                                                                     *              *      *                *      *             *
                                                                                                     ****************      ******************      ********|******
                                                                                                                                                           v
========================================================================================================================================================[FIFO]=====
                                                                                                                                                         |
  **************     **************     *************     ***********************     ******************     ***********     *****************      *****v********
  *            *     *            *     *           *     *                     *     *                *     *         *     *               *      *            *
  * dummykwd_0 *0<--0*            *     *           *     *                     *0<--0* deinterleave_0 *0<--0*         *0<--0* alsacapture_0 *      * streamin_0 *
  *            *     *            *     *           *     *                     *1<--1*                *     *         *     *               *      *            *
  **************     *            *     *           *     *                     *     ******************     *         *     *****************      ******0*******
                     *            *     *           *     *                     *                            *         *                                  v
                     *duplicator_0*0<--0* dummybf_0 *0<--0* speexpreprocessor_0 *                            * align_0 *                        **********0*******
                     *            *     *           *1<--1* (aec, denoise, ...) *                            *         *          RouteB        * deinterleave_1 *
                     *            *     *           *     *                     *                            *         *                        ********0**1******
                     *            *     *           *     *                     *                            *         *                                v  v
****************     *            *     *           *     *                     *                            *         *     ***********      **********0**1******
*              *     *            *     *           *     *                     *16<------------------------1*         *     *         *0<---0*                  *
* filewriter_0 *0<--1*            *     *           *     *                     *                            *         *1<--0* mixer_0 *1<---1* speexresampler_0 *
*              *     *            *     *           *     *                     *                            *         *     *         *      *                  *
****************     **************     *************     ***********************                            ***********     ***********      ********************

运行例3之前,需要先安装speex库。

sudo apt install libspeexdsp-dev

运行例3:

# 两个参数指的是alsa playback pcm name和capture pcm name。
# 它们随着机器的不同而不同。
x86_64-linux-gnu/bin/larkexample3 plughw:0,0 plughw:0,0

如果没错误的话,播放和录音应该同时开始了。 录到的声音文件存放在./cap-16000_16_1.pcm

这个例子的源代码在此:larkexample3.cpp

例5:运行一个单播放路由,嵌入了 SoundTouch 以做音调、节拍、播放速率的调节

RouteA

 libblkfilereader.so   libblkformatdapter.so    libblksoundtouch.so   libblkpaplayback.so
  ****************      *******************      ****************      ****************
  *              *      *                 *      *              *      *              *
  * filereader_0 *0--->0* formatadapter_0 *0--->0* soundtouch_0 *0--->0* paplayback_0 *
  *              *      *                 *      *              *      *              *
  ****************      *******************      ****************      ****************

运行例5之前需要先安装 SoundTouch 库和 PortAudio 库。

sudo apt install libsoundtouch-dev
sudo apt install libportaudio2

运行例5:

x86_64-linux-gnu/bin/larkexample5

如果没错误的话,播放应该开始了。

在另一个shell里,

lkdb status                                   # 显示百灵鸟状态
lkdb setparam RouteA blksoundtouch_0 1 0.6    # 音调变低
lkdb setparam RouteA blksoundtouch_0 1 1.8    # 音调变高
lkdb setparam RouteA blksoundtouch_0 1 1.0    # 音调变正常
lkdb setparam RouteA blksoundtouch_0 2 0.5    # 节拍变慢
lkdb setparam RouteA blksoundtouch_0 2 2.0    # 节拍变块
lkdb setparam RouteA blksoundtouch_0 2 1.0    # 节拍变正常
lkdb setparam RouteA blksoundtouch_0 3 2.2    # 播放速率变快
lkdb setparam RouteA blksoundtouch_0 3 0.4    # 播放速率变慢
lkdb setparam RouteA blksoundtouch_0 3 1.0    # 播放速率变正常

这个例子的源代码在此:larkexample5.cpp

例7:运行一个带SoX效果器的单路由,输出到ffplay

RouteA

 libblkfilereader.dylib  libblkformatdapter.dylib   libblkdeinterleave.dylib  libblkmixer.dylib      libblksoxeffect.dylib       libblkinterleave.dylib  libblkfilewriter.dylib

  *******************     **********************     *********************     **************     ***************************     *******************     *******************
  *                 *     *                    *     *                   *     *            *0-->0* blksoxeffect_highpass_0 *0-->0*                 *     *                 *
  *                 *     *                    *     *                   *0-->0*            *     ***************************     *                 *     *                 *
  * blkfilereader_0 *0-->0* blkformatadapter_0 *0-->0* blkdeinterleave_0 *     * blkmixer_0 *                                     * blkinterleave_0 *0-->0* blkfilewriter_0 *
  *                 *     *                    *     *                   *1-->1*            *     ***************************     *                 *     *     (stdout)    *
  *                 *     *                    *     *                   *     *            *1-->0* blksoxeffect_lowpass_0  *0-->1*                 *     *                 *
  *******************     **********************     *********************     **************     ***************************     *******************     *******************

运行例7之前需要先安装 SoX 库和 ffmpeg

brew install sox
brew install ffmpeg

运行例7:

x86_64-apple-darwin/bin/larkexample7 | ffplay -i pipe:0 -f s32le -ar 48000 -ac 2 -autoexit

如果没错误的话,播放应该开始了。同时在ffplay的播放画面上,音频频谱正在被实时绘制如下:

larkexample7-1

在另一个shell里,

lkdb status    # 显示百灵鸟状态,找到高通/低通滤波器的块名称分别为'blksoxeffect_highpass_0'/'blksoxeffect_lowpass_0'
lkdb setparam RouteA blksoxeffect_highpass_0 0 800    # 只有高于800Hz的音乐信号输出到左喇叭

音频频谱实时绘制如下:

larkexample7-2

贴士:在ffplay的音频频谱中,红色代表左声道,绿色代表右声道。如果在某个时刻点某个频率显示为灰色,则表示左右声道在那个时刻的那个频率上能量均等。

lkdb setparam RouteA blksoxeffect_lowpass_0 0 800    # 只有低于800Hz的音乐信号输出到右喇叭

音频频谱实时绘制如下:

larkexample7-3

ffplay频谱颜色的实时变化验证了集成在 百灵鸟 路由里的sox效果器在实时生效。

这个例子的源代码在此:larkexample7.cpp

更多的例子

作者的博客文章:<我的工程师爸爸-音频应用DIY系列>通过一系列小故事展示了利用 百灵鸟 来编程解决生活中遇到的音频问题。

lkdb实时调试

百灵鸟 在一个进程里运行时,调试工具lkdb可以跟它通信,从 百灵鸟 获取信息,向 百灵鸟 发送命令。

Usage:
  lkdb status [--dot]
    - Print the lark running status
    - Print dot code if enabled '--dot' option
  lkdb newroute ROUTENAME
    - Create a named route
  lkdb newblock ROUTENAME SOLIB ISFIRST ISLAST [ARGS]
    - Create a block on the route from the dynamic load library
  lkdb newlink ROUTENAME RATE FORMAT CHNUM FRAMESIZEINSAMPLES SRCBLKNAME SRCBLKOUTEPIDX SINKBLKNAME SINKBLKINEPIDX
    - Create a link to link the source block and sink block on the route
  lkdb start ROUTENAME
    - Start the route
  lkdb stop ROUTENAME
    - Stop the route
  lkdb setparam ROUTENAME BLOCKNAME PARAMID [PARAMS]
    - Set parameter to the block in the route
  lkdb getparam ROUTENAME BLOCKNAME PARAMID
    - Get parameter from the block in the route
  lkdb delete ROUTENAME LINKNAME
    - Delete the link from the route
  lkdb delete ROUTENAME BLOCKNAME
    - Delete the block and associated link(s) from the route
  lkdb delete ROUTENAME !
    - Delete the entire route
  lkdb loglevel LEVEL
    - Set the logging LEVEL: 0=off 1=fatal 2=error 3=warning 4=info(default) 5=debug 6=verbose
  lkdb setdump DIRECTORY
    - Enable dumping log & data when DIRECTORY is a valid path
    - Disable dumping log & data when DIRECTORY is --

除了以上例子中显示的实时打印状态、设定参数功能之外,lkdb还可以操作音频路由、抓取路由快照、改变日志等级、设定音频数据转储等。

不用写代码编译,通过lkdb跑一个跟例1一样的路由

在一个shell里,

x86_64-linux-gnu/bin/larkexample0    # 运行百灵鸟

在另一个shell里,

$ lkdb newroute RouteA
Created RouteA
$ lkdb newblock RouteA libblkfilereader.so true false examples/kanr-48000_16_2.pcm
Created blkfilereader_0 from libblkfilereader.so on RouteA
$ lkdb newblock RouteA libblkalsaplayback.so false true
Created blkalsaplayback_0 from libblkalsaplayback.so on RouteA
$ lkdb newlink RouteA 48000 S16_LE 2 960 blkfilereader_0 0 blkalsaplayback_0 0
Created lnk_0 on RouteA
$ lkdb start RouteA      # 音乐播放应该开始了
Started RouteA
$ lkdb stop RouteA
Stopped RouteA
$ lkdb delete RouteA !
Deleted RouteA

这个例子的源代码在此:larkexample0.cpp

通过lkdb抓取例3路由的快照

当例3运行时,

lkdb status --dot | dot -Tpng -o larkexample3.png

路由快照会被存成文件larkexample3.png

larkexample3.png

注意:这个功能需要graphviz(dot)先安装到您的机器。

sudo apt install graphviz

创建您自己的音频路由

第1步

在您的脑海中设计好路由。那些预编译好的块(像gain, mixer等)可以直接使用。如果您想要客制化的块,您可以自行编译动态库。 BlkPassthrough.cpp是一个块源码的例子。 参考MANUAL.md - 4 Build Your Own Block以获取更多信息。

第2步

在您的进程里调用 百灵鸟 的API来实现您的路由。样例已经列出。参考用户手册以获取更多信息。

常见问题与回答

Q1: “块”是什么?“端点”是什么?“链接”是什么?“路由”是什么?

A: 一个“块”就是一个软件DSP处理单元。它从一个动态加载库里被创建,并被 百灵鸟 路由所管理。它接受最多32路输入(即输入端点)数据,处理它们,把处理后的数据填入输出端点(最多32路输出)。 通常情况,一个端点代表一个声道音频,然而一个端点也可以运载多声道。例如“interleave”块的一个输出端点就可以运载多声道。 一个“链接”连接一个块的一个输出端点(作为源)至另一个块的一个输入端点(作为汇)。 一个“路由”是一个由多个块连接成的链条(或者图)。

Q2: 在一个机器上,我可以同时运行几个 百灵鸟 实例?在一个 百灵鸟 中,我可以创建几个路由?在一个路由中,我可以创建多少个块?多少个first块?多少个last块?

A: 在一个机器上,只有一个进程被容许创建一个 百灵鸟 实例。也就是说,一个机器运行一个 百灵鸟 实例。lkdb会跟这个唯一的 百灵鸟 实例通信。在一个 百灵鸟 中,最多可以创建26个路由,它们的名字需要被手动指定为"RouteA", "RouteB", ..., "RouteZ"。对于每个路由,名字是需要的,并且应该固定为"Route#"(大小写敏感),这里“#”代表[A-Z]。 在一个路由里,创建块没有数量限制。所有从一个路由里创建出来的块/链接都属于这个路由,也就是意味着它们的资源是被这个路由统一管理。 同样,创建first块和last块也没有数量限制。

Q3: 什么是“first块”?什么是“last块”?

A: 在一个路由里,至少需要创建一个“first块”和一个“last块”,这些块在创建的时候,都有“first”标志和“last”标志被各自指定。 这样的话,路由就可以知道从哪些块开始处理,到哪些块结束处理。从first块到last块之间,所有的块应该要被连接起来,不要有切断。只有所有连接都完整了,路由才可以启动。如果路由中间有切断,这是被容许的,但是路由就无法运行。如果您强制运行,路由将会进入BROKEN_RUNNING状态,直到切断被再接起来。

Q4: “多路由”跟“单路由多first块”有何不同?如果我有多路输入作为first块,我要如何在“多路由”和“单路由多first块”之间做选择?

A: 一个路由用一个线程处理数据。通常情况,“单路由多first块”可以工作地很好。在这种情况下,多输入以同样的步伐提供数据帧,并且它们不应该被相互阻塞。例如,一个输入是alsacapture,一个输入是filereader。 需要用到“多路由”的场景是,当多个输入放在一个路由里运行会有机会相互阻塞时,那么它们就应该被分离到多个路由。例如,一个输入alsacapture,一个输入是echo-reference。

基于百灵鸟的开源应用

  • kplay - 一个可以实时调音的WAV文件播放器
This is free and unencumbered software released into the public domain. Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means. In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. For more information, please refer to <https://unlicense.org>

简介

一个免费、轻量、功能强大的软件音频DSP,让您像搭积木一样构建音频系统。 A free, lite and powerful software audio DSP that enables you to build your audio system like building blocks. 展开 收起
C++ 等 3 种语言
Unlicense
取消

发行版 (23)

全部

贡献者

全部

近期动态

加载更多
不能加载更多了
C++
1
https://gitee.com/wksuper/lark-release.git
git@gitee.com:wksuper/lark-release.git
wksuper
lark-release
lark-release
master

搜索帮助