wav文件声音频率分析_游戏编程算法与技巧读书笔记第六章·声音

ffe198a116ddce8653045d48f3a9fbda.png

本章首先讲如何将原始数据转换成代码控制的音效。然后讨论更高级的声音技术,比如多普勒效应、数字信号处理和音效遮挡,它们都会在很多情况下用到。

一、基本声音

声音播放最基础的级别就是在游戏某个时刻播放某个音频文件。但是在多数情况下一个事件不是必须对应到一个声音上的。比如角色每次脚碰地设置多种脚步声随机选择播放。

还有一个要考虑的事情就是只有有限数量的频道可以同时播放。假如一个游戏有大量的敌人在玩家附近奔跑,如果全部都播放脚步声,那么有可能将所有的频道用完。有很多声音比敌人的脚步声更重要,因此我们需要将音效进行优先级排序。大多数游戏都存储了一组额外的数据描述了音频文件的优先级。

1.原始数据

原始数据是指音效设计师使用类似Audacity这样的工具来创建的最原始的音频文件。一个常见的方式为将短音效存储为WAV格式或者其他无压缩文件格式,而存储长音效,比如声音或者对话,则会采用压缩格式比如MP3或者OGG。

当在游戏中需要播放这些声音文件时,通常由两种方法。一种方法是让场景预加载短音效文件到内存中,这样到了播放声音的时刻就不再需要花时间到硬盘加载了。而另一种方法,由于压缩的声音或者对话文件通常会有更大的体积,通常会以6流 的方式加载。

2.声音事件

声音事件映射了一个或者多个原始数据文件。声音事件事实上是由代码触发的。所以比起直接播放fs1.wav,可能调用一个叫“footstep”的声音事件会更好。这个想法就是声音事件可以包含多个声音文件同时还能有元数据,将这些声音文件作为整体。

二、3D声音

大多数2D音效都是位置无关的。但是对于3D音效和3D游戏来说,音源的位置就特别重要。大多数音效都有自己独特的随着监听者距离增大衰减的方式。

1.监听者和发射者

不管监听者怎么监听游戏世界中的音效,发射者就是发射特定音效的物体。比如说,如果有一堆柴火发出噼里哗啦的声音,就会有一个声音发射器放在哪个位置然后发出噼里啪啦的声音。然后基于监听者和火柴声的发射者之间的距离就可以算出音量的大小。发射者相对于监听者的朝向决定了哪个喇叭有声音。

由于监听者回监听所有3D世界中的声音,所以摆放监听者的位置和朝向就很重要。如果监听者摆设不对,3D声音系统会有问题——要么声音太小或者太大,要么喇叭出声音的方向不对。

对于很多种游戏来说,直接使用摄像机的位置和朝向就可以了。但是有些游戏却不适用,比如第三人称动作游戏。

如果监听者与摄像机在同一个位置,这个声音听起来就像在几米或几十米外。简单的解决方法就是将监听者的位置和朝向设置到角色身上。但会有一个更大的问题,可能会导致喇叭出声音的方向不对。简单来说就是,会发生发射器在玩家的左侧,而在摄像机的右侧的情况,声音就可能会从左边的喇叭出来,这样就会看起来不正确。因为我们看到了爆炸在屏幕的右侧发生就会预期在右侧的喇叭播放爆炸声,而不管玩家的朝向。

在游戏《指环王:征服》中,开发者做了一定的妥协。首先就是我们让监听者的朝向等于摄像机的朝向,而不是等于角色的朝向。接着,与监听者位置准确地摆放在玩家身上或者摄像机身上不同,他们放在了两者之间。换句话说,监听者的位置就是摄像机位置和角色位置的差值结果。两者间的百分比通常介于33%和66%之间都能有不错的效果。

2.衰减

衰减描述了音效的音量随着远离监听者会如何减小,可以用任何可能的函数去表达衰减。但是,由于音量的单位分贝是一个对数刻度,线性衰减会产生对数变换关系。这种线性分贝衰减函数通常都是默认方法,但是显然不是唯一的方法。

3.环绕声

不少平台都不支持环绕声的概念——大多数移动设备最多只支持立体声。但是,PC和家用机游戏是可以有两个以上喇叭的。在5.1环绕系统中,会有总共5个正式的喇叭和1个用于表现低频效果的低音炮。5.1配置的优点就是会感受到更多方向的声音。

fcfe9b5c31f81d0e1aac28edc8fcf2e5.png

图 一个标准的5.1环绕声配置

三、数字信号处理

广义上讲,数字信号处理 (DSP)是计算机中表示的信号。在音频领域中,数字信号处理说的是加载音频文件然后在修改之后得到不同的效果。简单例子就是加载音频文件然后增加或减小它的音高。

看起来离线处理好这些效果,然后在游戏中播放也许会更好。但是运行时使用数字信号处理理由就是它能够节省大量内存。假如有一款剑击游戏,有20多种在野外开阔场地录制的武器碰撞音效。如果游戏中有多种场地会发出声音,除了野外之外,还有洞穴、大教堂等等其他地方。

这时候,在洞穴中发出的声音和在野外发出等声音听起来完全不一样。特别是在洞穴中,会有回声的效果。不用数字信号处理的话,那就得为20多种刀剑声针对不同场地录制成倍的音效。现在如果需要所有战斗音效,游戏内存很快就会被用尽。但是如果有了数字信号处理效果,就只需要根据场所调整成相应的音效即可。

实现数字信号处理需要线性系统和高级数学运算的知识,比如傅里叶变换。

1. 常见数字信号处理效果

游戏中常见的数字信号处理效果就是之前提到的回声。一个非常流行的回声效果库叫做Freeverb3。Freeverb3是一个冲量驱动系统,就是说为了对任何音效实现回声效果,需要一个音频文件表达在特殊场景播放的数据。

另一个大量使用的数字信号处理效果就是音高偏移,特别是多普勒偏移。音高偏移会通过调整频率增加或者减小音效的音高。多普勒偏移很常用,比如赛车游戏中引擎的音高会随着速度的变化而变化。

游戏中大多数的数字信号处理效果通常都会修改频率的范围或者输出分贝的级别。举个例子,一个压缩机缩小了音量的范围,导致很小的声音得到了增强,同时很大的声音得到了减小。通常用于统一多个音频文件,让它们保持相似的范围。

另一个例子是低通滤波器,通过删减频率的方式减小音量。在游戏中很常见的就是当玩家附近发生爆炸时的嗡鸣声。为了实现效果,时间会拉长,然后应用低通滤波器,接着播放嗡鸣声。

2.区域标记

通常只有关卡的一些区域才需要使用某些效果。比如说,如果一关里有野外区域和洞穴,回响效果可能只有在洞穴才会有。最简单的方式就是在地面上标记凸多边形。

985f9fef201f359b420385a8ff54646d.png

图 凸多边形和凹多边形

使用凸多边形的原因就是,给定一个凸多边形我们更容易判断一个点在凸多边形内部还是外部。给定角色的位置,就很容易判断角色是在多边形内部还是外部。如果角色在区域内部,回响效果打开,在外部则关闭。

但是,我们不想玩家已进入区域就马上产生效果,否则效果会比较刺耳。这意味着,玩家进入标记区域之后,我们希望渐渐地开启回响效果,这样效果听上去更加平滑。

值得注意的是使用凸多边形标记区域会有一个问题。就是如果标记区域在关卡中上下重叠,而这些区域又有不同的数字信号处理效果,这个方法会失效。举例就是,上方有一篇草地,下方由一个隧道,都标记了凸多边形区域。这个问题可以使用绑定盒之类的方式来解决。

四、其他声音话题

1.多普勒效应

在街上,一辆警车打开警报器向你靠近时,随着警车的靠近声音变得尖细(即频率变高,波长变短),相对的,在警车不断远离时,声音变得低沉(即频率变低,波长变长)。这种现象称为多普勒效应(或者称之为多普勒偏移),原因是因为声波在空气中传播需要时间。靠近的时候,连续的声波都比前一个要早到,远离时,则是晚到。

有趣的是多普勒效应不仅在音波中出现,而是所有与波相关的情况中都会出现。例如光波。

在游戏中,动态多普勒效应只会在高速移动的对象身上应用,比如汽车。技术上来讲,也可以在子弹上应用,但是由于太快,通常只播子弹飞走的声音。可以使用数字信号处理效果来实现多普勒效应。

2.声音遮挡

声音遮挡指的是当声音被障碍物遮挡住的时候,会有低通滤波的效果,意味着高频率声音的音量被移除了。这是因为低频率的音波比起高频率更容易传播。声音遮挡的另一个输出就是整体音量的降低。

相似但是不同的现象是声音衍射。通过声音衍射,声音可能不再是直线传播的了,但是还是有可能穿透障碍物。比如说,如果你朝柱子另一边的人大喊,声波会被柱子衍射,一个有趣现象是分割之后的音波可能会以不同的顺序到达,左边的音波可能比右边的音波早到,那么另一边人可能会听到两次声音。

检测遮挡和衍射的方法就是发射者构造一系列指向监听者附近的弧形。如果没有一个向量能直接到达,那就是遮挡。如果有一些向量能够到达,那么是衍射。如果全部都能到达,那么是Fresnel声学衍射

870070d9d449205341d6296f4c9da308.png

图 声音遮挡(a) 声音衍射(b) Fresnel声学衍射(c)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
WAV 文件中提取声音特征通常涉及以下步骤: 1. 读取 WAV 文件:使用 Java 的音频输入流(AudioInputStream)读取 WAV 文件。 2. 转换音频格式:将读取的 WAV 文件转换为所需的音频格式。例如,如果你要使用快速傅里叶变换(FFT)来分析声音特征,则需要将音频转换为带有 16 位采样的 PCM 格式。 3. 分析声音:使用 FFT 算法对 PCM 格式的音频数据进行频谱分析,得出音频信号的频率分布。 4. 提取声音特征:从频谱数据中提取所需的声音特征。例如,你可以使用峰值检测算法来确定音频信号的主要频率,或使用自相关函数来计算音频信号的周期性特征。 以下是一个基本的 Java 代码示例,用于从 WAV 文件中提取音频特征: ```java import javax.sound.sampled.*; import java.io.File; import java.io.IOException; public class AudioFeatureExtractor { public static void main(String[] args) { File audioFile = new File("audio.wav"); try (AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(audioFile)) { // 获取音频格式 AudioFormat format = audioInputStream.getFormat(); // 转换为带有 16 位采样的 PCM 格式 AudioFormat pcmFormat = new AudioFormat( AudioFormat.Encoding.PCM_SIGNED, format.getSampleRate(), 16, format.getChannels(), format.getChannels() * 2, format.getSampleRate(), false ); // 转换音频格式 AudioInputStream pcmAudioInputStream = AudioSystem.getAudioInputStream(pcmFormat, audioInputStream); // 读取音频数据 int numBytes = (int) pcmAudioInputStream.getFrameLength() * pcmFormat.getFrameSize(); byte[] audioBytes = new byte[numBytes]; int numRead = pcmAudioInputStream.read(audioBytes, 0, numBytes); // 分析声音 double[] audioData = new double[numRead / 2]; for (int i = 0; i < audioData.length; i++) { int sample = (audioBytes[i * 2 + 1] << 8) | (audioBytes[i * 2] & 0xff); audioData[i] = sample / 32768.0; } // 提取声音特征 // TODO: 在这里添加你的声音特征提取算法 } catch (UnsupportedAudioFileException | IOException e) { e.printStackTrace(); } } } ``` 请注意,此示例仅演示了如何读取 WAV 文件并转换为 PCM 格式,你需要添加自己的声音特征提取算法以完成任务。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值