《一场内心的万物复苏》讲师专访——赵靖

适合手机应用的高品质声卡——TOPPING E 1X2 OTG 评测

杜比全景声监听控制器的奥秘:Ginger Audio 终极解决方案和性价比可以兼得

旗舰级的监听耳机新标杆:Sennheiser 森海塞尔 HD 490 PRO 监听耳机首发体验

零基础到专业制作人:HEMe 全新概念的培训 + 作品发行计划新年再出发!

Reaktor 求最大值

曾照南 添加于 2017-08-14 ·

分享到微信

暂无评论

作者:Dreason

求最大值,又是一个常见的数学问题了;如果让你求两个数的最大值,这是一个多么简单的问题,那如果让你求一组数的最大值呢?同样这个问题其实也不难,我们只需要把这组数的第一个数跟下一个数比较,倘若大于下一个数,那么第一个数仍然继续跟下下个数比较,而倘若小于下一个数,那么下一个数就跟它的下一个数比较,然后这样的步骤一直重复着,直到所有数都比较完后,最后的那个数就是最大的数。(图1)


图1

好吧,不管你看得懂还是看不懂,让我们带着这个问题到Reaktor去探讨;没错,标题就是最大值的一些应用,那么知道它能有什么用呢?我们想想如果把它放到信号处理上面来,我们是不是可以去求出一段波形的峰值,注意这里所指的“峰值”是正的数值,那么问题来了,对于负值信号就有意义了,假设想让负值信号有意义的话,我们必须要让整段信号的所有值都变正,这样所有数我们都能处理到,也就是最后信号的“峰值”在原信号中可能是一个正值也可能是个负值,关键你的疑问是求这个“峰值”出来到底要来做什么呢?其实有一个非常直接的应用,那就是Normalize,说白了就是让信号永远限制在-1到1这个范围内。

不过说到峰值,Reaktor其实有为我们提供了一个叫Peak Detector的模块。(图2)



图2

这个就是一个很好去求最大值的模块,当然这个模块有个特性,那就是它在变化到下一个数值的时候有个缓冲的时间,也就是说对于Rel输入来说,它能来快速或者缓慢地控制最大值的变化,如果你想要去实现一个Normalize,可以把Rel的数值设置更大些,让最大值始终在一个较恒定的数值之间做微小的变化。

但对于Peak Detector模块,我们兴许不需要用到它Rel的部分,可能我们单单只是针对求一段信号的最大值,也就是只要求这段信号最大值是哪个就可以,至于它之后最大值是否会变化,就让它直接变化到下一个最大值,不用做一个缓冲的变化。

好的,问题应该很清楚了,也就是如果给你一段超过正常信号范围的声音,怎么让它的声音回到正常信号范围,假设这段声音超出的信号没有被切掉,或者说如果我们把几个波形加在一起,我们如何确保它们叠加后的波形最大振幅不会超出-1到1这个正常数值范围。

不是有Peak Detector模块吗?可能很多人会在上面讲完后会这样说,好吧,如果我不说Peck Detector模块,也假设Reaktor根本就没有Peak Detector这样的模块,试问下自己能做到吗?

这个问题的难度就是我们要怎么去把一个叠加后的波形的所有样点列举出来一个接着一个比较下去,在开始之前,我们先来看看我之前用Core Cell实现的一个求最大值的,尽管它看上去是可以帮助我去求出一个信号的最大值,但有个最大的问题在于它无法实时去更新这个最大值的变化,举个简单的例子,如果你一个信号的最大峰值在2,那么突然在某个时间段信号变到-1到1这个范围,那么它此时的最大峰值不可能再是2了,你明白我的意思吗!?(图3)


图3

图3的构建是真的可以简单去求两个数的最大值,可它也是忽略了我上面提的实时变化的可能性,因为有时候我们在调节几个叠加波形会造成这个波形振幅的变化,所以显然这样的构建是无法达到实时更新的目的,但其实我们可以分段去求最大值,也就是说我们可以把一个信号分成几段来分别求最终的最大值,比如举个波形的例子,假设一个波形是由1000个样点组成的,那么我们可以把这1000个样点分成2段500样点或者5段200样点等等来分别求每段的最大值,而这里有个细节要注意的是,每段的最大值都是独立的,意思就是第一段的最大值不能代表下一段的最大值。

好吧,上面讲的是不是越来越不好理解了,没关系,我们来操作下就会明白了。

首先,我用Core Cell的Macro搭建了一个重新采样的处理。(图4)


图4

这里你可以看到图4里的搭建结果是每1秒重新求一次,当然Max默认是44100个样点(看你声音采样率具体设置而定),我们也可以随时去改动它,所以我们可以结合图3的搭建来求分段后的最大值。(图5)

图5

OK,显然上面的搭建已经比之前的好一点点了,至少它实时去更新最大值,不过我们同时也发现更新不是马上就能得到结果,而是需要时间处理的,这也很正常,因为我们上面Max默认是44100,也就是1秒的时间,也就说它每次都是1秒更新一次,实际上我们也可以重新给Max设置不同的数值来看看,我们会得到Max数值越小,更新的速度就越快,这样也会导致一个问题,就是最大值的波动性,尽管如此,但这个参数却帮我们去调整最大值的稳定性,不过我们倒是可以针对这个采样率进行切分。(图6)


图6

注意切分采样率后,我们需要给它取整,如果不取整的话会导致最大值无法求出,因为Resample的部分永远都是整数的,整数永远不等于小数点位数上不等于0的浮点数。

当然到这里算是可以结束了,如果你想要继续给它更进,甚至你可以添加一个Smoother来让最大值变化更连续些,但是对于搭建我们最后其实应该还需要再考虑初始化的事情,因为不管你求了多少次最大值,就连没有任何信号经过的时候,那个最大值永远都在,所以我们需要让在没有信号经过处理的时候,状态恢复到0,于是最后我们可以增加信号等于0的情况来改变初始化的状态。(图7)


图7

接下来我们继续来讨论一个很老的问题,也是我以前一直比较纠结的问题,那就是Retrig;至于为什么要来讨论Retrig,那是因为突然某一天我在玩Blocks的时候,发现有个Note In的Block让我找到思路了,一时间顿时泪流满面,当然对于Note In关于Retrig内部的实现(图8),它显然更复杂了,这里我想把它更简单化,简单化的结果其实就是在求最大值。


图8

好吧,如果你看得懂图8的搭建并能自己做一个,那么接下来我所讲的,你都可以忽略。

OK,我们也顺手来做一个,看看它是怎么用到求最大值的。

首先我们先来理清一下思路,是这样的,我们要记录音高的变化,也就是说你每按一个音符都要被记录下来,但是究竟应该怎么来记录呢?当然不是说一个音符数值是60,就把60记录下来就行,而是要有标记地记录,就像一开始你按一个音符数值是60,那么这个音符数值60就给标记个数字1,接下来你再按一个音符数值是72,那么这个音符数值72就给标记个数字2,然后依次类推,最后这样一堆带有标记的音符被记录下来,如果这个时候让你去求最近按的音符是哪个,你知道是哪一个吗?答案很明显,我们只需要知道最后一个被标记数字的就可以了,换句话说就是所有被标记数字中最大的那个数字代表的就是最近按的音符。

好吧,让我们回到Retrig的问题上来,Retrig的意思就是当你按一个音符不放,然后接着又按一个音符,当你释放第二个音符的时候,第一个一直按的音符就会被重新触发,说白了就是当你同时按两个音符,比如音符60和音符72,那么如果你放开音符72,这个时候音符60会重新响应,相反如果你放开音符60,那么音符72也会重新响应,用声音来理解的话就是相同的音符会发声两次,通常性我们在键盘上同时弹两个音符,两个音符都会发声,但这个时候你突然释放一个音符,另外一个被你按住的音符按道理是不会发出声音的,所以这个就是Retrig的原理,目的就是要让那个被你按住的音符再响一次,不过我们也知道这个的前提是前面还有事先要有一个音符被按住后被释放才能有这样的响应。

行,让我们再次回到上面用数字标记音符的方法,如果把它放到Reaktor上去实现的话,应该怎么来做呢?其实我们是可以利用Core Cell的Array数组模块来实现,比如我们给Array模块的Size设置128,至于这样设置是因为我们知道对于Midi Note,它的取值范围在0到127,长度刚好也是128个,所以我们是可以利用Midi Note的数值来作为索引值指向Array的读写位置,然后接下来就是Gate的问题,我们知道按一个音符它不仅仅只是对音符做出响应,它也会有Gate响应,对Reaktor来说就是Note Pitch模块和Gate模块,那么Gate模块输出的数值就可以作为标记数字的触发,这里就要用到一个数数的模块,让Gate模块大于0的时候触发累计数值,因此我们其实可以这样来构建。(图9)


图9

注意上面“++”它是一个Macro,它就是一个非常简单的累加器,而对于“0”的Macro,它就是一个触发0的简单搭建,我们也看到对G(Gate)的处理,判断它大于0的时候就累加数值,等于0或者小于0就设置为0,这样一来的好处是我们可以更好地去求最大值,举个简单的例子,比如你开始按一个音符60,那么它标记为1,接着你按一个音符72,它标记为2,如果让你比较那个标记数字最大,无疑是第二个音符72,那么这个时候如果你释放了音符72,Gate就会变成0,变成0的情况就是同时会触发音符72标记数字变成了0,那么这时肯定是音符60标记数字最大了。

好的,那么接下来我们就要来读取所有被标记的数字,比较它们,看看哪一个才是最大值,直接给出结果:(图10)


图10
我们来分析上面为什么会这样子,首先,我创建了一个Index,它会不停地依次输出0到127,因为我需要读取Array所有标记的数字,接着对于读出的所有标记的数字,我需要给它进行下一轮的比较并求最大值,然后在每次求出标记数字中最大值的时候利用Latch去触发Index,这样就可以得到Retrig的结果了,当然图10的搭建只是一个处理,真正有没有起作用的在于P和G,也就是说如果你用Note Pitch模块是不能得到Retrig的结果,而是要用Channel Message模块(图11)才能实现,它跟Note Pitch模块唯一的差别在于,Channel Message模块的Nr输出不仅仅只输出一次音符值,当你释放后,它也会再次输出一次你释放的那个音符值,比如你同时按音符60和音符72,当你释放音符72,Nr会再次输出音符72的音符值,尽管我们看数字是不能知道什么,当然你可以通过Counter模块去测试一下就知道了,而当你这个时候又把按着的音符60释放,那么Nr就会输出音符60的音符值,这跟Note Pitch模块输出有本质上的差别了,因为Note Pitch模块压根不会这样做。

图11

到这里你可能觉得图11已经完成了Retrig,但很多人最后往往会忽略掉Gate的部分,也就是你还需要一个Gate输出,而这个Gate输出是由Pitch来决定的,就是说每次Pitch改变,都会产生一个Gate信号,这个我们倒是可以通过Hold来实现,很简单的方法是直接用Reaktor提供的Hold模块,或者我们也可以在Retrig内部自己搭建一个Hold,相信有看过我之前写的关于Core Cell搭建日记应该知道一个Hold该怎么搭建,这里就不再详细说明了,直接给出结果。(图12)


图12



可下载 Midifan for iOS 应用在手机或平板上阅读(直接在App Store里搜索Midifan即可找到,或扫描下面的二维码直接下载),在 iPad 或 iPhone 上下载并阅读。

文章出处 http://magazine.midifan.com/detail.php?month=2017-08#19

转载文章请注明出自 Midifan.com

暂无评论