语音识别相关算法一般在MATLAB上进行仿真验证与实验,在工程上一般还是在VS中进行实现落地,本系列将介绍语音信号处理在C语言中的一系列应用,后期将以此为基础,再落地移植到嵌入式平台。
今天介绍SoundTouch语音变速不变调算法的工程应用。SoundTouch是一个支持音频倍速播放的开源库。支持变速(加速减速)、变调、变速同时变调等三类功能模块,能够对流媒体实时操作,也能对音频文件操作。采用 32 位浮点或者 16 位定点,支持单声道或者双声道,采样率范围为 8k~48k。
自己之前应用sonic进行变速不变调处理时,也得到了了一定的效果,但相比于SoundTouch,整体效果确实差了一些,网上此前有同学也做过对比,但sonic实现简单,所以一开始采用的是sonic变速不变调,但后期主要由于sonic合成的时长控制,语音数据都不及SoundTouch,这次跑通了SoundTouch的变速不变调实例,做一下记录,网上资料主要基于 android或者是其他编译平台的经验介绍,自己的需求是需要C++进行调用,所以本工程基于SoundTouch的C源码实现的,(原工程已经迭代到VS2019,自己在VS2015上亲测可以跑通),话不多说,开干!
SoundTouch官网
SoundTouch地址:http://soundtouch.surina.net
SoundTouch 库适用于编写需要速度/音高控制功能的声音处理工具的应用程序开发人员,或者只是用于播放声音效果。SoundTouch 库源套件还包括一个示例实用程序 SoundStretch,用于从命令行界面处理 .wav 音频文件。
SoundTouch 库特点:
(1)开源实现;
(2)使用GNU C 编译器 (gcc)或Visual C++支持任何处理器和操作系统平台:Windows、Mac OS、Linux 和其他*nixes、Raspberry Pi、Android、Apple iOS等等;
(3)支持 16 位整数和 32 位浮点单声道/立体声/多声道音频格式;
(4)可以进行实时音频处理;
(5)最大输入/输出流延迟 ~ 100 毫秒;
(6)使用 133 Mhz Intel Pentium 处理器或更好的处理器可以实现 CD 质量立体声的真实处理;
(7)通过单个 C++ 类实现简单的编程接口;
(8)C++、C# 和 Java 示例应用程序;
(9)用于从 C#、Pascal/Delphi 和 Java 调用 SoundTouch 库例程的 API 接口模块;
(10)使用针对 x86 处理器的 MMX 和 SSE 指令集优化以及针对通用多核 CPU 的 OpenMP 优化的 C++ 实现。
点击官网上图中源码链接:https://codeberg.org/soundtouch/soundtouch
SoundTouch源码链接
进入源码网站,点击上图标记位置,进行下载
下载后解压到当前文件夹(下载文件为soundtouch-master.zip,解压为soundtouch)
进入解压文件soundtouch文件夹目录下…\soundtouch\source\SoundTouchDLL\DllTest
文件夹,
双击DllTest.vcxproj,以VS2015打开工程如下图所示(包含三个工程,主要是互有调用,所以需要一起进行编译运行)
根据输出栏的提示信息:
E:\PROJECT\VS\soundtouch\source\SoundTouchDLL\SoundTouchDLL.vcxproj : warning : 无法找到 v142 的生成工具。安装 v142 可使用 v142 生成工具进行生成。
E:\PROJECT\VS\soundtouch\source\SoundTouch\SoundTouch.vcxproj : warning : 无法找到 v142 的生成工具。安装 v142 可使用 v142 生成工具进行生成。
E:\PROJECT\VS\soundtouch\source\SoundTouchDLL\DllTest\DllTest.vcxproj : warning : 无法找到 v142 的生成工具。安装 v142 可使用 v142 生成工具进行生成。
修改三个工程的生成平台,以SoundTouchDll为例,右键进入工程属性页,可以看到
将目标平台版本修改为:8.1(电脑为win7系统时修改,win10应该不用修改)
平台工具集修改为:v140 (v140为VS2015,v142为VS2019)
点击确定即可保存
同样的,将SoundTouch与DllTest工程的属性也修改为目标平台版本修改为:8.1,平台工具集为v140
点击生成中的重新生成解决方案
生成成功!
变速不变调例程在DllTest工程,右键点击DllTest工程,设为启动项,
再右键点击DllTest工程,点击“调试”,选择“启动新实例”,弹出以下窗口
点击“是”,弹出缺少库信息,缺少SoundRouchDllD_x64.dll库
回到解压库soundtouch的lib文件夹中
复制SoundRouchDllD_x64.dll与SoundRouchDllD_x64.lib放到DllTest.exe同目录下
重新调试,没有报错信息,即调试成功,下面介绍语音变速不变调例程实现
首先复制一个原语音infile.wav到工程目录下(DllTest目录,DllTest.cpp的同级目录)
打开DllTest工程中的DllTest.cpp文件
修改DllTest.cpp源码如下
///
/// DllTest.cpp : This is small app main routine used for testing sound processing
/// with SoundTouch.dll API
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
#include
#include
#include
#include "../SoundTouchDLL.h"
#include "../../SoundStretch/WavFile.h"
using namespace std;
// DllTest main
int main(int argc, char *argv[])
{
// Check program arguments
/* if (argc < 4)
{
cout << "Too few arguments. Usage: DllTest [infile.wav] [outfile.wav] [sampletype]" << endl;
return -1;
}*/
//const char *inFileName = argv[1];
//const char *outFileName = argv[2];
//string str_sampleType = argv[3];
const char *inFileName = "infile.wav";
const char *outFileName = "outfile.wav";
string str_sampleType = "short";
bool floatSample;
if (str_sampleType.compare("float") == 0)
{
floatSample = true;
}
else if (str_sampleType.compare("short") == 0)
{
floatSample = false;
}
else
{
cerr << "Missing or invalid sampletype '" << str_sampleType << "'. Expected either short or float" << endl;
return -1;
}
try
{
// Open input & output WAV files
WavInFile inFile(inFileName);
int numChannels = inFile.getNumChannels();
int sampleRate = inFile.getSampleRate();
WavOutFile outFile(outFileName, sampleRate, inFile.getNumBits(), numChannels);
// Create SoundTouch DLL instance
HANDLE st = soundtouch_createInstance();
soundtouch_setChannels(st, numChannels);
soundtouch_setSampleRate(st, sampleRate);
soundtouch_setPitchSemiTones(st, 2);
soundtouch_setTempo(st, 2);
//soundtouch_setTempoChange(st,100);
cout << "processing with soundtouch.dll routines";
if (floatSample)
{
// Process file with SoundTouch.DLL float sample (default) API
float fbuffer[2048];
int nmax = 2048 / numChannels;
cout << " using float api ..." << endl;
while (inFile.eof() == false)
{
int n = inFile.read(fbuffer, nmax * numChannels) / numChannels;
soundtouch_putSamples(st, fbuffer, n);
do
{
n = soundtouch_receiveSamples(st, fbuffer, nmax);
outFile.write(fbuffer, n * numChannels);
} while (n > 0);
}
}
else
{
// Process file with SoundTouch.DLL int16 (short) sample API.
// Notice that SoundTouch.dll does internally processing using floating
// point routines so the int16 API is not any faster, but provided for
// convenience.
short i16buffer[2048];
int nmax = 2048 / numChannels;
cout << " using i16 api ..." << endl;
while (inFile.eof() == false)
{
int n = inFile.read(i16buffer, nmax * numChannels) / numChannels;
soundtouch_putSamples_i16(st, i16buffer, n);
do
{
n = soundtouch_receiveSamples_i16(st, i16buffer, nmax);
outFile.write(i16buffer, n * numChannels);
} while (n > 0);
}
}
soundtouch_destroyInstance(st);
cout << "done." << endl;
}
catch (const runtime_error &e)
{
cerr << e.what() << endl;
}
return 0;
}
重新调试运行DllTest工程
调试成功!
生成一个outfile.wav文件,生成语音信息如下
oufile.wav语音已加速一倍
变速指令为第68行(soundtouch_setTempo与soundtouch_setTempoChange军可以进行变速不变调,但两者参数范围不一样)
soundtouch_setTempo(st, 2);
//soundtouch_setTempoChange(st,100);
两个函数的定义(SoundTouchDll.cpp中)
cooledit查看两段语音
可以看到处理的非常不错,相比sonic确实好不少。
最近项目上需要对WAV语音进行处理,这个是对语音进行加速减速播放时需要保证语音不失真,目前工程已经可以跑通,但目前SoundTouchDll源码工程DllTest需要包含两个工程,所以下一篇文章将介绍将三个工程进行整合,合并到一个工程中,后续再整合到一个函数中,即可直接对语音进行变速不变调调用处理,完成调试后再进行具体的介绍。