音频处理中的变调和时间拉伸(一)

2023-10-31 23:30

本文主要是介绍音频处理中的变调和时间拉伸(一),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

介绍

很多用过磁带或者塑胶唱片的人都会对于一种现象感到熟悉:当我们快放或者慢放音频的时候,如果我们用两倍速度快放,除了会使得音频播放时间减少一半,还会使得音高升高一个八度,听起来音频中的人声会很像卡通动画人物的声音。同时,如果慢放会使得播放时长增长并且降低相应比例的音高。

以前使用模拟音频录音技术的时候,这种现象可以通过设置错误的播放速度来复现。现在,在数字信号处理领域,同样的现象可以通过重采样来实现。

重采样会同时改变音频的播放时长与音高,但是有时人们会有需求:只改变音高或者只改变播放时长。这类技术会被称为:

  • time/pitch scaling,
  • time/pitch shifting,
  • time stretching.

应用

Time scaling 可以慢放音乐速度,方便大家跟着跳舞或者拍视频再或者练习乐器。慢放讲话录音可以帮助人们转写,或者学习语言,盲人可能会使用快放来播放一些音频书籍来节约时间。视频网站上的倍速播放页需要音频跟着加倍但是不会变调。

类似的,在卡拉OK或者练习唱歌的时候,调整音乐的音调或者key,可以更好的匹配演唱者的声线。或者用来调音,百万调音师你们懂得。

最后,有些人可能想要通过改变他们自己声音的音调来实现身份隐藏。

实现方式

目前有两种实现上述技术的基本方式,即在时域处理或者频域处理

时域处理方式直接操作采样数据,比如后面要介绍的SOLA算法。时域处理的优势在于实现非常直接(straight-forward),因为音频数据处理时的采样格式跟它播放时或者录制时相同。缺点在于会产生一些人造回响导致失真,并且随着更大的时间调整,失真更明显。比如时间伸缩超过15%时。

频域处理是将采样声音转换为短时的 频率/振幅 成分然后在频域信息上来做伸缩,相位声码器是这类方法的一个典型。频域处理的优势在于可以支持更复杂的声音调整给出更好的听感,因为人类听力根本上只是基于频率的。

然而,由于它们明显的强大和优雅,频域处理实现起来更加复杂,计算复杂度更高。所以受限于计算资源,比如cpu速度和内存等。

SOLA

SOLA即 Synchronous-OverLap-Add,同步交叠相加法。通过将声音数据切成一系列的很短的长约几十到几百毫秒的片段,然后将这些片段通过一定的手段:跳过某些内容或者重复某些内容,重新排列起来达到比原始音频更长或者更短的播放时间。使用相同思路的算法还有TDHS(Time-Domain Harmonic Sampling),WSOLA和PSOLA,他们的区别在于实现细节。

为了避免在两个片段连接处的声音出现过于明显的断裂感,两个片段会有一定的重叠部分,所以声音的振幅从一个片段到另一个片段是渐变的,所以SOLA名字中有OverLap-Add部分。

最简单的SOLA实现可以使用统一的片段长度,然后每隔一段均匀的间隔来取一段片段。如果你想让声音缩短10%的长度,假设我们使用100毫秒(+叠加的长度)的片段长度,然后以110毫秒为间隔,从原始音频中取片段,然后将这些片段通过叠加连接起来,你就获得了想要的效果。同样的如果要延长10%的长度,选择100毫秒的片段,然后每隔90毫秒取一个片段,最后连接起来即可。是不是很简单呢?

然而,实际应用中的SOLA实现起来并没有那么简单。选取片段的时候不管片段内容的话,即使采用了渐变叠加的方法还是会由于过大的不连贯而出现噪音。(注:这里的不连贯是指的采样点不构成一个波形,虽然其实采样点实际上是连贯的,但是不构成波形的话,发出的声音也是噪音)

实现考虑

为了满足音质要求,SOLA在实现上需要在选择片段时,使得相邻片段之间交叠部分尽量相似。

实际上,音频流每次处理一个片段,为了使得相邻两个片段之间更匹配,在选择下一个片段的时候,可以在一个合适的窗口范围内来寻找。一种寻找最匹配片段的方法是通过计算上一个片段结尾部分和窗口内的待选片段的开头部分的互相关性,具有最高互相(cross-correlation)关值的两个片段的头尾是最相似的。这些片段最后通过交叠的方式连接在一起,形成了新的音频流,并且与原始的音频流长度不同。

SOLA的总体算法如下图所示。图中坐标轴的范围是可以任意设定的,所代表的时间单位仅做示意。在算法执行过程中,原始的音频会被切成合适长度的若干片段。新的片段会在与前一片段合适的间隔后被选出,从而获得想要的伸缩效果。

图1
在图1中,第一个片段从0开始,然后长度是7个时间单位,首尾各有一个时间单位的交叠部分。每隔9个时间单位取一个片段,最终的时间伸缩比例为 (7-2)/9 = 0.555,也就表示相对原始音频缩短了44.5%的时长。

然而,实际上在取片段时,并不是严格按照名义上的时间间隔来取的,而是取自以时间间隔处为中心的一个窗口范围内。比如图1中的“New Sequence”实际上是取自第8个时间单位到第10个时间单位之间,以便让新的片段和前一个片段在交叠时可以更好的重合。在图1下半部分我们可以看到交叠后的结果。

互相关函数对于评估音频片段的相似度很有效,并且也易于实现。同时,还有一些其它的相似度测量函数也被提出。其中一种方式是将片段的边缘与声音的节拍对齐,如果声音有一定的节拍并且可以被检测到,那么这种方式可以降低产生的类似混响感的人工处理痕迹。还有一种方式是评估频域频谱的相似度,而不是时域的波形相似度。

SOLA只需要基础的加法和乘法,因此可以使用整型或者定点数运算来实现,防止浮点数运算不被支持或者效率不高。

多声道处理

处理立体声时,片段交叠操作应当是在多个声道同样的位置进行的,如果我们单独处理每个声道,最终可能会造成声道之间错位。

所以我们可以同时处理所有声道,比如,可以将所有声道相加后再通过互相关函数找到共同的最优的片段获取点。

使用SOLA进行变调

SOLA只有拉伸功能,但是如果和重采样技术结合起来就可以实现变调功能了,很简单,假如要升高八度,只需要下采样音频到原始长度的一半,然后再使用SOLA拉伸到原始长度即可。

修音痕迹与参数

使用SOLA处理过的音频会有一点点回声的痕迹,这种痕迹会随着拉伸的幅度的增大而变得更加明显。

有一种减轻回声痕迹的方式是通过根据被处理音频的基本频率来选择处理片段时长。(这里的基本频率不是f0,意思是被处理音频的节拍频率)

处理时窗口范围的选择也会影响音质,越宽的窗口范围一般会获得更好的交叠音频的匹配度。但是,太宽的话产生的音频会不稳定,听起来像是在“漂移”。

交叠长度,一般是整个处理片段长度的一部分。通常使用线性的响度变化会表现的更好。

这篇关于音频处理中的变调和时间拉伸(一)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/318855

相关文章

Java controller接口出入参时间序列化转换操作方法(两种)

《Javacontroller接口出入参时间序列化转换操作方法(两种)》:本文主要介绍Javacontroller接口出入参时间序列化转换操作方法,本文给大家列举两种简单方法,感兴趣的朋友一起看... 目录方式一、使用注解方式二、统一配置场景:在controller编写的接口,在前后端交互过程中一般都会涉及

Java 中的 @SneakyThrows 注解使用方法(简化异常处理的利与弊)

《Java中的@SneakyThrows注解使用方法(简化异常处理的利与弊)》为了简化异常处理,Lombok提供了一个强大的注解@SneakyThrows,本文将详细介绍@SneakyThro... 目录1. @SneakyThrows 简介 1.1 什么是 Lombok?2. @SneakyThrows

在 Spring Boot 中实现异常处理最佳实践

《在SpringBoot中实现异常处理最佳实践》本文介绍如何在SpringBoot中实现异常处理,涵盖核心概念、实现方法、与先前查询的集成、性能分析、常见问题和最佳实践,感兴趣的朋友一起看看吧... 目录一、Spring Boot 异常处理的背景与核心概念1.1 为什么需要异常处理?1.2 Spring B

python处理带有时区的日期和时间数据

《python处理带有时区的日期和时间数据》这篇文章主要为大家详细介绍了如何在Python中使用pytz库处理时区信息,包括获取当前UTC时间,转换为特定时区等,有需要的小伙伴可以参考一下... 目录时区基本信息python datetime使用timezonepandas处理时区数据知识延展时区基本信息

Python的time模块一些常用功能(各种与时间相关的函数)

《Python的time模块一些常用功能(各种与时间相关的函数)》Python的time模块提供了各种与时间相关的函数,包括获取当前时间、处理时间间隔、执行时间测量等,:本文主要介绍Python的... 目录1. 获取当前时间2. 时间格式化3. 延时执行4. 时间戳运算5. 计算代码执行时间6. 转换为指

Python Transformers库(NLP处理库)案例代码讲解

《PythonTransformers库(NLP处理库)案例代码讲解》本文介绍transformers库的全面讲解,包含基础知识、高级用法、案例代码及学习路径,内容经过组织,适合不同阶段的学习者,对... 目录一、基础知识1. Transformers 库简介2. 安装与环境配置3. 快速上手示例二、核心模

一文详解Java异常处理你都了解哪些知识

《一文详解Java异常处理你都了解哪些知识》:本文主要介绍Java异常处理的相关资料,包括异常的分类、捕获和处理异常的语法、常见的异常类型以及自定义异常的实现,文中通过代码介绍的非常详细,需要的朋... 目录前言一、什么是异常二、异常的分类2.1 受检异常2.2 非受检异常三、异常处理的语法3.1 try-

Java中字符串转时间与时间转字符串的操作详解

《Java中字符串转时间与时间转字符串的操作详解》Java的java.time包提供了强大的日期和时间处理功能,通过DateTimeFormatter可以轻松地在日期时间对象和字符串之间进行转换,下面... 目录一、字符串转时间(一)使用预定义格式(二)自定义格式二、时间转字符串(一)使用预定义格式(二)自

Python使用getopt处理命令行参数示例解析(最佳实践)

《Python使用getopt处理命令行参数示例解析(最佳实践)》getopt模块是Python标准库中一个简单但强大的命令行参数处理工具,它特别适合那些需要快速实现基本命令行参数解析的场景,或者需要... 目录为什么需要处理命令行参数?getopt模块基础实际应用示例与其他参数处理方式的比较常见问http

Java Response返回值的最佳处理方案

《JavaResponse返回值的最佳处理方案》在开发Web应用程序时,我们经常需要通过HTTP请求从服务器获取响应数据,这些数据可以是JSON、XML、甚至是文件,本篇文章将详细解析Java中处理... 目录摘要概述核心问题:关键技术点:源码解析示例 1:使用HttpURLConnection获取Resp