音频变速 | libsonic 开源库的介绍与实践 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
glumess
V2EX    Android

音频变速 | libsonic 开源库的介绍与实践

  •  
  •   glumess 2021-11-01 09:51:46 +08:00 12346 次点击
    这是一个创建于 1439 天前的主题,其中的信息可能已经有所发展或是发生改变。

    在做音视频编辑的时候,大家关注更多的是视频开发,热衷于 FFmpeg 、OpenGL 这些技巧,实际上音频开发也是很重要的,甚至可以说音频开发比视频开发更难一点。

    对音频的常见处理就是变速、变调、混音这些,一般都是用开源库来搞定,常见的就是 libsonic 和 libsoundtouch 两个,当然有实力的公司会自己研发音频算法。

    本篇文章会简单介绍 libsonic 的使用。

    lisonic 获取

    libsonic 是一个支持音频倍速播放的开源库,并且支持大于 2 倍速的播放,它的主页地址如下:

    https://android.googlesource.com/platform/external/sonic/+/refs/heads/master/doc/index.md

    可以通过该链接下载 libsonic 库:

    git clone git://github.com/waywardgeek/sonic.git

    这个仓库里面内容还挺全的,包含了 Java 和 C 版本的实现和使用演示,很方便做移植。

    如果你只需要用到变速和音量调整,那么使用 sonic_lite.h 和 sonic_lite.c 两个文件就行了,这里面对功能做了裁剪。

    libsonic 主页上还提供了一个 Android NDK 版本的仓库,通过该链接可下载:

    git clone git://github.com/waywardgeek/sonic-ndk.git

    不过这个版本有的太老旧了,还是 Android.mk 的接入方式,现在都换成 CMake 接入了。

    有兴趣的同学可以写一个 sonic-ndk CMake 版本的封装库,说不定能在 Github 上刷一波 star 呢。

    libsonic 使用

    libsonic 的调用接口不多,具体使用完全可以参考给的代码演示。

    以下是一个音频倍速的使用代码:

    /* Run sonic_lite. */ static void runSonic(char* inFileName, char* outFileName, float speed, float volume) { waveFile inFile, outFile = NULL; // 定义输入和输出的 buffer short inBuffer[SONIC_INPUT_SAMPLES], outBuffer[SONIC_INPUT_SAMPLES]; int samplesRead, samplesWritten, sampleRate, numChannels; // 打开输入文件,并且获取输入文件的相关信息 inFile = openInputWaveFile(inFileName, &sampleRate, &numChannels); if (numChannels != 1) { fprintf(stderr, "sonic_lite only processes mono wave files. This file has %d channels.\n", numChannels); exit(1); } if (sampleRate != SONIC_SAMPLE_RATE) { fprintf(stderr, "sonic_lite only processes wave files with a sample rate of %d Hz. This file uses %d\n", SONIC_SAMPLE_RATE, sampleRate); exit(1); } if (inFile == NULL) { fprintf(stderr, "Unable to read wave file %s\n", inFileName); exit(1); } // 打开输出文件 outFile = openOutputWaveFile(outFileName, sampleRate, 1); if (outFile == NULL) { closeWaveFile(inFile); fprintf(stderr, "Unable to open wave file %s for writing\n", outFileName); exit(1); } // 初始化 sonic 并且设置速度 speed 和音量 volume sonicInit(); sonicSetSpeed(speed); sonicSetVolume(volume); do { // 从输入文件中读取 sample samplesRead = readFromWaveFile(inFile, inBuffer, SONIC_INPUT_SAMPLES); if (samplesRead == 0) { sonicFlushStream(); } else { // 将读取的 sample 给到 sonic 中的 sonicStream // sonicStream 会根据 speed 和 volume 做相应处理 sonicWriteShortToStream(inBuffer, samplesRead); } // 将 sonic 中 sonicStream 处理后的数据给到 outBuffer // 并将 outBuffer 写入到输出文件中 do { samplesWritten = sonicReadShortFromStream(outBuffer, SONIC_INPUT_SAMPLES); if (samplesWritten > 0) { writeToWaveFile(outFile, outBuffer, samplesWritten); } } while (samplesWritten > 0); } while (samplesRead > 0); closeWaveFile(inFile); closeWaveFile(outFile); } 

    这个代码示例还是比较简单易懂的。

    首先是检查输入和输出文件是不是有问题,这一点很基础但也非常重要。

    代码中用到的示例文件是 wav 格式的,libsonic 仓库中有对应的资源可以下载,不用自己满世界找文件了。

    wav 文件的读取可以用仓库中的 wave.c 和 wave.h 文件操作。

    接下来就是从输入文件中读取 sample ,并交由 libsonic 处理,最后将处理好 sample 写入到输出文件中。

    这有个概念就是:视频的处理,我们都是说一帧一帧的,音频就没有帧的概念,一般都是说采样点,比如要处理多少个采样点之类的说法。

    代码示例中,readFromWaveFile 方法从文件中读取 sample ,sonicWriteShortToStream 方法将 sample 交由 libsonic 处理。

    libsonic 中有个 sonicStream 的结构,它用来存储变换后的数据,这里面会根据设置的 speed 和 volume 做处理。

    最后再通过 sonicReadShortFromStream 将数据从 libsonic 读出,然后通过 writeToWaveFile 方法写入到输出文件中。

    经过测试,以上方法确实可以实现音量调节和变速的效果,并且在变速的同时保持着原来的音调。

    小结

    以上就是关于 libsonic 的介绍与实践,除了 wav 格式文件,pcm 格式数据也同样可以做变速的。

    关注公众号 音视频开发进阶,在后续还会进行更新源码分析等更多内容,敬请期待~~~

    8 条回复    2021-11-01 18:01:04 +08:00
    shawndev
        1
    shawndev  
       2021-11-01 10:20:28 +08:00
    之前刚好接触过音频变速开发 ,当时了解的主要有 libsoundtouch 和 fmod ,libsonic 有哪些额外的优势吗?
    glumess
        2
    glumess  
    OP
       2021-11-01 10:23:38 +08:00
    @shawndev 可以支持高于两倍速的播放吧,另外在视频播放上比较好,libsoundtouch 侧重于音乐? 两个的实现方式不太一样。而且 libsonic 的接入方式很简单...
    minami
        3
    minami  
       2021-11-01 11:02:41 +08:00
    实测 libsonic 效果会比 libsoundtouch 差多少,相差不大的话感觉确实 libsonic 用起来更方便
    kimown
        4
    kimown  
       2021-11-01 12:14:06 +08:00 via Android
    lz 有音频合并的库推荐吗,就是多个 mp3 合并成 1 个
    glumess
        5
    glumess  
    OP
       2021-11-01 12:51:40 +08:00
    @minami 是的,这个也是看使用场景来区分了...
    glumess
        6
    glumess  
    OP
       2021-11-01 12:52:03 +08:00   1
    @kimown 我搜一搜看看,有没有好得库推荐
    xlsepiphone
        7
    xlsepiphone  
       2021-11-01 13:02:59 +08:00
    比 ffmpeg 的 atempo filter 有什么优势吗
    glumess
        8
    glumess  
    OP
       2021-11-01 18:01:04 +08:00
    @xlsepiphone 性能上没测过,可能包体积有优势吧,不用引入 ffmpeg 了
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2727 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 25ms UTC 15:00 PVG 23:00 LAX 08:00 JFK 11:00
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86