从“アニメソングの歌詞ならここにおまかせ?”关闭说起

警告:本文大量个人的无病呻吟。

无意间点开尘封多年的书签,震惊地发现,アニメソングの歌詞ならここにおまかせ?(网址:http://www.jtw.zaq.ne.jp/animesong/)这网站居然关闭了。

一番搜索,可以知道关闭的时间点是今年一月底,原因也没有多说,作者就是一句“感谢长久以来的支持”。

C4Eq6cuUoAA8Ssx.png large.png

(Via:Twitter

不过,从页面报错信息来看,直接原因是作者用来Host网站的服务(J:COM NET加入者向けホームページサービス)停止运营了。当然,如果作者真的想继续,换个服务商并不是不可能,但是果然有些时候事情就是欠个导火索。我喜欢吹日本人或者外国人的“根性”,能不辞辛苦、不计报酬(准确地说是倒贴钱)地维护这类爱好网站,但是果然一切都是有极限的。毕竟到后来大多都是惯性使然,突然弦可能就断掉了。

这件事我居然过了一个多月才发现,可以说是过去的我所不可想象的:没错,这网站应该是我正好10年前那会,不夸张地说上的最多的网站。说起这话题,似乎应该先从网站介绍起。如名字所示,该站是一个收集动画歌词的网站。作者按照作品分类,收集了大量动画歌曲的歌词,并按时(一般一周一两次)更新最新出的歌曲的歌词。另外值得一提的是作者是有JASRAC的牌照的,所以是完全合法运营。当然,这些歌词多数在无数日本其他歌词网站都能找到,但是作为一个只更新动画歌词的网站,有其独有的优越之处,这得从我当年的“工作”说起。

06年那会大概是我刚入宅的时候,相信很多人都知道了,契机就是一部《魔力女管家》。我当时着迷程度非常深,在网络上疯狂搜刮和魔力女管家有关的一切资源,其中自然也不会放过音乐。魔力女管家的BGM是非常优秀的(作曲:増田俊郎),歌曲也不错。主打的自然是麻幌的配音川澄绫子,唱了两部的OP以及一些插曲不说,更在各种相关CD里唱了大量歌曲,甚至单独出了一张专辑。几个配角也都有歌曲,其中男主的三个青梅竹马(?)还组成了一个组合叫“とりおまてぃっく”(很显然名字捏他作品标题「まほろまてぃっく」),包办了所有的ED,也出过张专辑。当年这些歌我翻来覆去也算是听到烂了,更是我Anison的入门。

既然有歌曲,自然少不了歌词。我在搜索魔力女管家的歌词的时候无意发现了一个叫“漫网”的论坛,上面就有一个区叫做动漫歌词区。当时这区还挺活跃的。里面的好多版主我几年后还经常在ASTOST见到。虽然不能记起全部,但是有位叫紫亚的妹子倒是蛮深刻,还玩翻唱来着。

魔力女管家的歌曲歌词慢慢收集齐了,但是在这过程中,我逐渐对动漫歌曲歌词这个东西本身感了兴趣。于是我开始经常在这网站上发帖。不过歌词从哪里来呢?这就不得不提到标题这个网站了。作为一个只更新动漫歌词的网站,自然比去那种什么都更的网站方便,而且最棒的地方在有这网站还有change log,每次更新了哪些一目了然,只要原样照搬就是了。虽然网站有防复制,但是实在是很弱一般开源代码复制就是了。当然还有一些别的网站,比如当年比较有名的月之舞歌词站(一个国产的日音歌词收藏站,早就挂掉了)等等,但是还数“アニメソングの歌詞ならここにおまかせ?”用得最多。

不过,虽然我最早知道的是漫网,也一直有在混,我真正驻扎下去的则是另外一个论坛:动漫花园之音乐花园。动漫花园本身的名气相信不用多说了,即使是到今天大部分人也知道,因为其BT站的缘故。不过最早的动漫花园是从字幕组起家(和PPG算是齐名),然后有论坛和tracker的。动漫花园论坛当年的有意思之处在于,其音乐分区是一个独立的网站,名字叫音乐花园,管理基本也独立。当时上面聚集了一些动漫音乐或者日音牛人,很多现在都还在AO混,比如牛叔(nalanchen,即现在“MGRT音花雪月”的组长,说来MGRT正是Music Garden RIP Team的意思),jedi_vs_sith等,不过我和这些大大都不熟,算是单方面认识。音乐花园当年还算是一个满活跃的网站,还经常搞些音乐精选集什么的:

Cover_Inside.jpg
当年的音乐精选集  vol.3的伪·封面

因为音乐花园人比起漫网(哦顺便说句,当年漫网主站是个卖动漫资源的网站)比较少的缘故,“抢发”歌词也不剧烈,我逐渐在这边的歌词区(名字叫词苑)活跃起来。后来也记不清是自己主动申请还是被邀请,总之稀里糊涂地当了歌词区的版主。

在音乐花园这边打交道比较多的是词苑的几个老版主,冰河的海,草上飞校长,以及最老资格的domonick。一些具体事情就不详细说了,我就记得当初年纪小,为了歌词翻译脸皮超级厚的疯狂追着屁股求助,而草上飞校长总是非常客气地帮我翻译,实在是感激不尽。dominick基本算是歌词区的奠基人了,早期的大量歌词、以及目录的整理都是他涵盖的,还请Ayumu(不知道是谁,可能是上古巨神)制作了两款相关的软件,转码用的Sapphire和注音用的Ruby:

QQ截图20170310005223

QQ截图20170310005218

其他的著名人士还有Shion(很多ID,其他的还有“水色”等),她在漫网和DMHY这边都有活跃,是个非常细心的人;Frank543,他后来制作了一个非常好用的跨站歌词搜索引擎Lyrics Get(自带破解防复制),现在还可以用哦。

至于我自己嘛,只做过一些微小的工作,多数就是搬运歌词,其中自己比较感兴趣的几部作品,比如当时迷的爱马仕系列整理的稍微用了些心。另外很多歌词尤其是很多角色歌,网上是没有的,需要自己从booklet里抄写下来。另外还用自己三脚猫的C#功夫写了一两个自动格式化发帖的辅助小工具之类的。

就这么过了两三年,国内早期的动漫论坛开始慢慢走向一个衰败期。音乐花园后来也被动漫花园吸收了回去,成为了里面的一个版块。接下来就是DMHY的分裂风波了。我不知道还有多少人今天还记得,总而言之就是站长“很闲”和一些会员的运营思路没走到一起。过程很复杂,形成了“站长派”和“元老派”,当年作为一个论坛的积极参与者,自然队站在了“元老”这边,好像还参与过一些撕逼,现在想想简直幼稚得可怕。经过一番周折之后(中间有段时间甚至有俩动漫花园论坛),最后的妥协是站长继续经营资源网(同时在这前后建立了u2)出走,其他论坛元老保留了论坛。后面的结局自然都知道了,资源网活得好好的,论坛死的比原来更快。讽刺地是,在几年之后的今天,论坛(的尸体)又回归了很闲的手下:https://bbs.dmhy.org/ ,我当年复出无数心血的词苑的时间也定格在了2010年。

也大概是因为这个事情,就像标题网站的站长一样,我逐渐地也倦怠了,词苑的工作慢慢就荒废了。哦其实中间还在ASTOST混过一段,当过那边的歌词区的见习版主,不过没坚持多久就是了(然而就几个月还很傻地和那边的小圈子对喷过一次,年轻真好)。

好了,莫名其妙的追忆就到此为止了。作为祭奠,我把最初的起点——我整理的魔力女管家歌词传到GitHub了。没错你没看错,所有的歌词页面的编码都是错的(Firefox的话手动选成GB2312就行。Chrome把编码选择阉割了我也没办法呀哈哈哈),毕竟这是我N年前用Word文档(原始文档/Google Doc版,更全一些,还有所有CD的曲目信息)转的……闲的话再搞个正常点的网页吧。

ReplayGain在UPnP media server中的应用和补遗

UPnP media server是个挺有用的东西。在PC端配合一个功能非常全面的foobar2000插件——foo_upnp,安卓端配合foobar2000 Mobile或是BubbleUPnP,即可轻松实现包括但不限:用手机播放电脑里的媒体库,用手机当电脑的音响用(呃延迟没测过,估计只够听歌),用手机控制电脑播放器,以及前面的全部反过来控制等功能。当然,最理想的情况是把media server设在诸如NAS之类的设备上,但是就我个人来说,最常用的应用场景是躺在床上耳机插手机听电脑的媒体库/播放列表。

既然前一段时间折腾了那么就RG,这也得用上不是。让我们先仔细研究一下foobar2000那边的server的profile设置。

qq%e5%9b%be%e7%89%8720170220192532

另外为了便于测试,将Basic Settings里设成始终使用默认profile和关闭增加兼容性的额外流:

qq%e6%88%aa%e5%9b%be20170220193855

可以看到大抵来说,有这么几种streaming的方案:源文件直出,转码为MP3,解码为WAV。

直出最好理解,就是在http上host对应的文件而已。直出可以保有原始文件的所有metatag,自然也就包括RG信息;这样,在移动端使用支持RG的客户端时(这里就是foobar2000 mobile了),就会读取到信息进行响度调整。

但是直出的局限性非常大。foobar2000 mobile支持的格式非常有限。TAK这种就不用说了,自然也不支持任何音频文件+cue的类型。不过倒也不会播不了,只是sever会自动无条件帮你转成WAV。最吊诡的是,像FLAC这种明明是支持的格式(即,你把歌曲拷贝到手机里是能放的),有时候会在foobar2k mobile那边出现播放列表里完全看不到的现象(不能稳定重现。与之相对,第三方的BubbleUPnP则很稳定不会有这个问题)。

既然直出这条路不行,那就只能转码或者解码了。介于局域网带宽对于音频来说完全不是问题,自然选择音质更好的WAV,也避免了二次压缩的问题。不过,转码/解码之后有一个问题,就是RG信息完全丢失。哪怕是转码成MP3也是一样。还好,在下面那个Audio processing里,和Converter(转码器)一样,可以设置转码/解码时的处理。注意这里既然叫processing那自然是硬编码进去,而不是靠RG信息。所以foobar2000 mobile端会识别成无RG信息,调整那边相应的RG设置时要注意(我则是完全关闭)。

哦从图中可以看到,你可以设置规则对不同文件类型设置不同的转码规则(例如有些转,有些直出等等)。但是没啥卵用,因为你一旦开启了processing,所有的都会被强制转一遍mp3/WAV,所以还是死了这条心。

这里又是和上一篇文章中提到的普通用电脑回放时一样,面对一个抉择:是选择全部降低到和RG目标响度一样的响度(即:较低的响度),还是全部增益到和“新歌”一致的一个比较高的响度。这里还是选择了前者,因为毕竟那样对音质的保存是最完整的,而且主要用耳机听歌的话也不用担心有输出不足的问题。具体来说,就是在Processing里开启apply RG,同时对无RG信息的歌曲(主要是响度大的新歌)加个-9.5 dB的pre-amp。如果还不放心可以再加个Advanced limiter(虽然99%的情况根本不会有任何区别),但是介于Advanced limiter目前有个会把1缩成0.9999的bug,还是别了罢。

当然这种选择下就会有一个问题,那就是和我手机里那些已经转换好的、响度和新歌一个水平的音频文件有冲突。而且因为两者都是无RG信息,也无法靠调整手机端的RG设置中pre-amp来弥补。不过还好我一般其他场合听歌是用Google Music而不是foobar2000 mobile,以后就用fb2k mobile专门听媒体库就是。

多说一句,客户端那边选用foobar2000 mobile而不是BubbleUPnP的原因倒不是fb2k mobile支持RG(毕竟在我的最终配置下也用不到),主要还是foobar2000 mobile支持手机端的last.fm统计插件,虽然BubbleUPnP的界面大概好一万倍(电脑的foobar我觉得还行了,手机那个真的是丑的惨绝人寰)。另外,BubbleUPnP有个很烦的地方就是每次我修改服务器端(我电脑)的UPnP设置那边就必须会自动切断连接,也就是退出所有的远程playlist啥的,我还得重新选,在测试的时候尤其烦。而foobar2000 mobile则是另外一个极端……不但不会断,他还会缓存一部分媒体的地址(其实就是个URL,可以在电脑端或手机端的console里看到),也就是说我切换了设置之后有时候得在那边强制退出一次来让他刷新URL(服务器端这边即使你修改了设置,老设置的URL实际上还是并没有禁用的,依然有效)和播放列表。

screenshot_20170220-193326
客户端(foobar2000 mobile)读取流媒体的log范例

UPnP媒体库播放的响度规格化这事儿到此也就告一段落了。不过,我又回头去想在移动设备播放歌曲的workflow能否有可优化的地方。

如前文所述,我目前在移动设备采用的是“新歌不变,老歌先RG再+9.5dB”的方案,原因是因为这样兼容性最好,对没有RG支持的播放器也能完美播放,而且不会有输出太低的问题(我手机插车上听,即使在这种设置下都几乎要开到最大音量才行了,如果全部都低9.5dB那可调整的余地就太小了)。当然最大的问题就是+9.5dB导致的超过full scale引起的削波问题。

解决方案上次也说过,就是在转换时再用DSP加一层Advanced limiter,把超出的部分动态调整到1以下。不过由于犹豫会对音乐的完美呈现造成影响(毕竟还是部分压缩了动态范围)我之前一直没用。不过最近遇到这么一首歌,一下子就听出削波的问题了(下载链接):

废话一下,歌曲是菊池桃子的「卒業 -GRADUATION-」,个人的五星歌曲。算是无数好听的叫“卒业”的歌曲之一(其他的还有尾崎豊的,斉藤由貴等等)。菊池桃子天使般的声线在这歌里得到完美的体现。咳跑题了。

这歌的问题在于动态范围极大,在我的传统转换设置下,自然会溢出full scale很多,事实上,其peak达到了1.40(+2.93 dBFS)之高。从1:00左右开始,就会疯狂爆音,用手机+耳机听时最明显。因此,Advanced limiter就是非常必要的了。我对比了下开启Advanced limiter的版本和原版,完全听不出区别(毕竟音量大于1的部分只是极小的spike,频段可能更不是人耳敏感的部分),可见这个limiter的效果比起一般的动态压缩要好得多,也解除了我之前的一大顾虑。

不过在研究过程中我发现一个有趣的事实:AAC(m4a)这个格式居然可以保存大于1的数值!也就是说,我上面发这个+过9.5dB的音频文件,其实并没有损失任何信息或者削波——超过FS的1.4的peak也完整地记录在了音频中。这说明了什么呢?如果你的播放流程在输送到DAC之前有足够的衰减处理(例如软件中的波形层面的音量降低,但包含音响上的Analog的音量旋钮),又或者你的DAC/Analog设备足够专业,留有headroom支持超过1的波形,其实并不会产生削波/爆音。对应到电脑,foobar2000里的volume就是个不错的例子(但是别忘了上文提到的Win7的自带的limiter适用过早的bug,所以避免);对应手机端,根据我的观察,至少安卓系统的音量是不行的(不过安卓的音频处理一直都臭名昭著):如果仅仅靠调整系统的媒体音量,该爆音的还是爆(不清楚安卓的系统音量具体原理是数字上衰减波形还是模拟级)。不过,foobar2000 mobile中有个单独的volume设置,通过那个,或者里面带的RG设置的pre-amp,可以做到同响度情况下(即先用foobar2000 mobile的音量降低几个dB,再在系统音量里稍微开大一点达到同样响度)完美无爆音播放上面那个m4a文件。

不过这个用起来其实也有颇多不便:第一个不便是foobar2000 mobile的音量设置……他有bug。每次切歌,音量就会回归到0dB,即使界面里显示的还是你的设置。另外还是上面说的问题了,如果你降了几个dB,那输出不够这老问题又来了。所以,我最终还是经过权衡选择了转换时选择高响度水平+Advanced limiter的方案。当然还有第三个方案:转换时不加Advanced limiter(利用m4a的特性保留超过1的数值),但在播放时靠foobar2000 mobile自带的DSP即时加。这样可以最大限度保存动态范围,以后这些mp4拷贝到电脑上听时还可以还原。我现在还在想要不要全面转成这样——因为如果这么做,就表示了我就锁死只能用foobar2000 mobile当手机播放器了,这方面有点犹豫。

前面说了AAC(m4a)可以保存高于full scale的数值,那相对地WAV、FLAC和APE就不行了,如果你转换过程中增益到超过1,最终出来的文件会被削波到1。当然FLAC/APE之类的是为了完美呈现WAV而故意这么设置的吧,大概。MP3则比较奇怪,还是上面那个歌,转换之后会出来个peak为1.075的玩意…大概和MP3算法有关吧。另外每个的平均响度也会细微的差别,理论上来讲很自然AAC会高一些(毕竟没削波),虽然差别很小就是了。

qq%e6%88%aa%e5%9b%be20170221233307
利用RG扫描来查看peak和平均响度。因为Gain是负值,所以绝对值越大说明响度越大。音频全部通过原始wav文件+硬编码进(RG+增益9.5dB)的方式逐一生成

所以很显然地,如果你是转成了FLAC之类的已经会直接削波的格式,即使上面那个很复杂的操作也没法拯救你这音频了,怎么放都会爆音,万万要避免。

嗯,最后附一个几种流程的图示吧。三脚猫ps功夫不要笑话(点击大图)。

blog.png

上面的是最终响度=RG目标响度的workflow,优点是基本无损,缺点是输出比较低。目前我在电脑和UPnP媒体库输送到手机两种回放方式时使用。可以看到新歌直接降低-9.5dB(图里写成9了…),老歌直接RG,两者会获得一个相对一致的响度,同时不破坏老歌的动态范围。注意这里的-9.5dB和RG都是纯粹回放时加的,原始音频是不经过修改的。

下面的是方法2,即最终响度=新歌平均响度的workflow。我在转换歌曲到单独m4a文件时使用此方法。优点是兼容性强,和大多数市面上现成的歌曲文件响度一致;缺点自然是对于高动态的老歌峰值会溢出。为了防止削波,如果是即时回放或转换成支持超过FS的格式(AAC/m4a)时,可以通过再加个digital音量调整拯救(这种情况下就依然无损动态范围),或者如图所示干脆直接最后加个可选的Advance limiter进去(可以是转换时的硬编码,可以是回放的DSP)。对于不支持超过FS的音频格式,这大概是唯一可以接受的转换方案)。

半场好戏——妖精的旋律【旧文】

10年的读后感,当年不知道为啥只发了Bangumi。


说来惭愧,身为一个ACG fan(自称),居然一直没有看过这部大名鼎鼎的作品。可以说在我刚入宅的05年,在学校vod看到这部介绍就觉得很重口,不过当时没见过市面,看了点寒蝉,以为日本动画这样也很通常,就一直撂那里没看。昨天整理硬盘突然看到几个月前下的这套漫画(台版翻译成「變異體少女」),再想想自己也算是个原作党,于是就开始看了。

故事讲述地球上最近突然出现一种长角的新人类——二觭人,他们命中注定要取代人类,而旧人类自然不会束手就擒,他们很早就开始将这种人类圈养起来研究对策,但是意外还是发生,一个实力最强的二觭人——露西,从实验室中逃了出来。故事因此开始。露西因为人格转换而变成了一个人畜无害的无知少女,被一家公寓「枫庄」的主人耕太收留。而他俩其实早就见过面——八年前,正是露西杀掉了耕太的全家,而露西由于人格转换、耕太由于在这样的冲击下失忆,两人却互不相识。随着时间的推进,研究所不断派来各种人员来捉拿露西,而男主人公的记忆似乎也随时可能恢复……

可以说,整个故事在前半段张力十足,前一秒还一副主角相的谁谁,下一秒就可能变成一堆肉块,作者用这种果断,这种「杀人不眨眼」的功夫,很好地塑造出了二觭人的残忍恐怖特性;另外一方面,虽然出场人物不算很多,但是每个人都个性分明,而且几位女主人公都背负着悲惨的过去,可以说打下了一个不错的基调。但对我来说感触最深的却在于,作者笔下的女孩们那略显空洞的眼神加上大量的绯红,给人一种随便触碰就会坏掉的感觉,非常非常让人想怜惜(吐槽下,露西和娜娜变身后那御姐形象完全不喜…)。尤其是娜娜,从她一出场我就被迷倒了,她那种对父爱的渴求的感觉,实在是… 当然还有真理子,可以说,藏间和他两个女儿之间的爱恨情仇这条线,就是整部漫画最精华的部分。当真理子抓着露西爆炸之后,故事已经达到了他的最高潮(但是很可惜,作者并不这么想,所以这里渲染并不够,而且这场戏排的也不好,否则感人程度肯定可以再上升)。至此,作者成功地导演了半场好戏,如果故事在这里戛然而止(当然,如果真要这么做,得来AfterStory或者之前把二觭人和研究所那档子事儿讲清楚),那对我来说可以封神;但是很可惜作者并没有这么做。

但也许作者根本没有做好长期抗战的准备,在故事的后半段剧情开始急转直下,可以说在真理子之后,作者墨迹了5、6卷,在剧情上也基本没有什么实质性的发展了,说难听了感觉就像在骗稿费。如果说你要把二觭人的来龙去脉说清楚也不是不可以,但是用整整5卷来讲……?作者你也辛苦了。在这样苍白的故事发展下,别的一些问题开始大量暴露,比如剧情的前后不一致——比如到后来,二觭人似乎变得不再那么不可战胜,甚至某些情况下苍白无力;没错,人类方的武器是有提升,但是拜托编的圆一点,靠那样一个人都杀不死的破弹弓打二觭人,我没法接受。当然相反的,二觭人也会莫名变强,前面铺垫了那么久的触手长度,后面也不重要了,反正实在不行二觭人还会爆种嘛。比如前面伏笔的浪费,真由前面被后爸性侵犯过,而之后看到男主(被Nyu强迫)摸Nyu胸时还露出了很异样的眼神,但是后面也就这样不了了之了;真理子用自己生命换来露西的角断掉,而后面台词是「啊露西已经死了,现在她只是人畜无害的Nyu了」,但是后面露西不是随随便便又出来了?!而且角又长的更大了。最让我无语的是那个荒川(角泽的女助手,最后研发出疫苗那位),前面以为她后来必然有大作为,结果这个人整个就是一说相声的,尤其在那个岛要崩坏的时候一边逃一边和那个队长说冷笑话,完全是无厘头。再比如最后露西在地下湖碰到了角泽和那个巨型怪物,这终极对话本来可以玩的更有意思点,结果就是露西三下两下刮死那怪物,然后再刮死角泽和他那儿子(说他他儿子我又要喷了,这娃出场一共不到一话,你是来打酱油的??)…其实角泽自己并不是二觭人而仅仅是头骨异化这么好、这么讽刺的点子,我可以说我自己完全就没有想到,作者你要是好好经营一下,比如哪怕描写一下角泽知道之后那种「整个世界掉入漩涡」的感觉,相信这结局的档次至少能上两个台阶,结果这样的好包袱就这么埋没了。而男主人公(其实我觉得他根本不算主人公)在过完了属于自己的家家之后,后面的作用也虚无化,感觉就是为了结局时和露西缠绵几下而已,而且还突然变得非常中二……实话说,前面其实也算是他的线,但是风头全部被某个女儿控的大叔抢走光啊…

我个人而言,是比较讨厌剧情中出现什么新的人物,大概是一种不愿意接受改变的心理作祟;但是很明显对于一部作品,应该不断有新鲜血液加入,作者逐渐维护一个更大的人物关系交织的网,故事的格局才会因此而变大,而不是只有三四个人自己的过家家,尤其是对于这部张口闭口毁灭全人类的漫画来说。但是很可惜,作者显然有点小家子气了,打来打去还都是那几号人,甚至发指到真理子死了之后作者为了不浪费人设(喂),又套用模型造人造人出来。而一些新人物的出现,要么是功能性极强,要么是根本不知道他的作用,而最多的情况是直接给人作者想表达「啊,我终于编出来个新人物」的感觉。比如那第二个研究所,突然搞出来这劳什子干嘛?

到了后来另外一个问题是,读者对那些重口味的东西已经麻木,而作者反而越来越「仁慈」了。且不说战斗场面的残酷给人带来的刺激会下降很多这点,作者后来不知道是不是改信佛了,死的人越来越少,几个主人公都能在受极重伤的程度下存活,实在是太狗血,你当你是海贼王吗!不是我觉得一定要死人才能煽情,而是作者你自己拉高了读者的口味。前面坂东(就是那个SAT的暴力男)被露西整的右手断掉、双目失明的时候,你也许会有所感触;但是后来你再看到他连肠子都炸出来的时候,反而没了什么感觉;而如果看到他在故事的结尾,又走了出来的时候,你是否会掀桌呢?读者早就习惯了一会儿掉个胳膊一会儿缺根腿什么的,残肢已经不能再当成卖点了啊,作者!其实坂东的安排还算好了,至少时间上拉开了,就当是一个番外的Happy Ending;而之前的藏间为了真理子之死而拔枪自尽,结果几话之后你发现他原来被坂东救了没死成;前面男主为了挡子弹刚中枪,没几话你发现他原来只是肺穿孔;这种的才更让人有很强烈的「被耍了」的感觉。我觉得如果让我安排,结局我会安排让由香抑或真由死掉。二觭人怎么也非我族类,而且本身就是杀人机器,如果作者敢于让主角5人组中这两位完完全全的普通女孩牺牲,哪怕只是失去几个胳膊腿的话,我相信给人的冲击会猛烈得多。当然了,可以看出作者最后根本就只是想要一个大团圆结局而已,那么牺牲的只能是露西。

接下来讲一下在本篇作品里出现的两个元素——人格转换和失忆。这两个元素,可以说在各种作品中早已被用滥,其原因很简单:非常好用!对于编不下去的地方——玩失忆,玩分裂!简直是居家旅行杀人越货必备良品。如果你不是写搞笑作品,对于这两项你应该非常谨慎的使用,用好了是增加戏剧性,用不好了——那就是都合主义了,怎么方便怎么编。对于本部作品,可以说先天底子不错,一个变种人,玩玩分裂也无可厚非;男主受到那么大冲击失忆了也可以理解嘛。而且作者一开始还是很谨慎的,有人来抓我了我就是露西,平时我就是Nyu陪男主过家家,不是没有违和,但是可以接受。但是后来呢?当你看到露西可以在子弹射到肉里的时候紧急变身,将子弹弹出的时候,我想不用我再多评论。关于失忆这点本来没什么好说的,不过我想说些别的地方的一些所谓「主动失忆」:比如真由看到露西大战娜娜,她却认为那都是看错了,来自我麻痹;而男主一直中二地叫「Nyu没有杀人」,甚至完全不会有一丝怀疑,我也没什么话好说了。

还有一个很有意思的命题是于二觭人定位的思考。对于这样注定要取代新人类的物种,我们应该赶尽杀绝,还是和平共处? 抑或,就干脆被他们征服?作者没有明确给出答案,但是我个人感觉作者倾向于赶尽杀绝——首先,在他的笔下,二觭人被塑造了一个无差别杀人的残忍性格,最大的表现还不在什么三岁就会杀人这些描述上,而在于经常发生的一种场景:前一秒二觭人还在和你交谈,似乎也没有话不投机,结果下一秒你的你已经身首分离。根本就搞不清你为啥就死了。这种杀人的随意性,实在是让人类很难以接受这样的物种。当然,作者也是有对他们的怜悯的,但多建立在几个特定的角色之上,对于整个群体而言,作者并未流露出太多的感情。

最后,还有些乱七八糟的感想,不单独成章了。作者的画风可以说在第一卷时惨不忍睹,尤其是人物的脖子——每个人都向前伸着脖子的诡异模样,太惊悚了… 幸亏后面有很大改善,从第二卷之后基本就不会关心这个问题了。作品名称叫作「妖精的旋律」,在最后时刻露西死前唱了望美交她的歌,也算是点了题。不过看到那时候我一是已经很困,而是已经被后半段白开水的剧情摧残的不行了,也没剩下多少感触就是了…作者之前还画过一个同名读切(一话完),而且是他的处女作,也有一并收录在单行本之中,不过那画风,那剧情,我觉得还是不提也罢…刚翻看百度百科,看到这么一条:「在漫画原作中,旺太的小狗姿态只是伪装,其实它是拥有不死之身的生命体」……我的妈呀居然还有这么一出,我居然一直没想到……难怪那狗N次都没死……不过这种设定有意义吗?!莫非作者在玩票?另外这狗和露西小时候那条是一条吗………?嘛不管了不管了。

总体而言,虽然只是半场好戏,但是这依然是部不错的作品,评分的话7星吧。有人总吐槽说我写的读后感多半是在骂,这是实话,主要是很多时候作品的好,实在是难以用语言来描述,难免词穷;但是缺点说起来却很容易就滔滔不绝……嗯,还是那句话,大家批判地看。看动画的一些介绍,动画对本作改动比较大,而最关键的在于剧情只到前七卷,就是我所谓的「高潮」那里,说不定能拍出更好看的故事,有空找来看看。

补充几句关于真由吧。很喜欢的角色,而且其人物塑造上比起来也是比较丰满的。

只有12岁,就因为被继父虐待而离家,走时甚至连裙子都没有穿(她是在继父准备再次故技重施时逃跑的),下身穿着内裤就跑了出来。后来她碰到了从主人那里跑掉的汪太,两个相依为命,她在那个海滩边上的棚子里和汪太一起吃面包边的场景,很是温馨。而在汪太被主人要走、卖面包的店要搬走这个对她来说简直是末日一样的那个生日,她一个人在那里哭的场景,更让人难忘。还记得她刚到枫庄的时候,看到食物流下口水的那个可爱的表情。

在后来,同样是在那个棚子里,他照顾了坂东和藏间两个重要人物,和娜娜关系最好最熟悉的也是她,可以说她串起了很多重要的剧情。她也在枫庄找到了属于自己的幸福,我前面有说过最好剧情把她写死会加强作品的感觉,但是果然即使让我来写,我也下不了这个手。

ReplayGain、音量规格化与实战应用

又一个兔子洞(笑)。

ReplayGain和响度

故事开始前,大概得先讲讲到底什么是ReplayGain,以及为什么我们需要它。

响度规格化

一言以蔽之,ReplayGain是用来规格化(Normalize)音乐,或者说数字音频文件,的响度(Loudness)的。但是这里要非常小心术语,因为规格化这个词有很多不同的应用。控制动态范围——即“最响”和“最安静”之间的差别,这个有时候也叫作“规格化”(例如在PotPlayer中),但是在音频世界里,更常用的说法叫“压缩”(Compress)。可以看到,一个音频在单纯经过“压缩”之后,其平均响度可能并不会变,但动态范围会变小。这可以解决诸如“电影声效太大,人声小到听不见”之类的问题(但是注意:这并不是一个“正确”的解决方案。至少对我个人来讲,多数动态压缩滤镜听感极差),不过在混音界 Compressor 更常用的用法是指控制输出的范围,便于后期处理。可以看到,一个音频如果经过压缩,其声音特征就改变了。比如艺术家的本意就是这里是悄悄话,那里是爆炸声,结果压缩之后两者的差距就缩小了。因此,在播放音乐时,一般是不应该引入压缩的。

响度规格化,包括ReplayGain,则不同,它要解决的是这么一个问题:不同音轨之间的平均响度差别很大,用户播放时需要不停地调整音量来获得一个相对舒适的响度。在经过响度规格化之后,一个音轨本身的动态范围理想情况下应该不变,但是会整体地提升或者降低,从而达到音轨于音轨之间相对一致的响度。

既然知道了目标,那实现原理其实就不难理解:只要找到一种测量平均响度的方法,然后分别测量每个音轨的响度,然后再设定一个标准(Reference),比较两者不同,补上差值就行了。

不过这里有俩问题:一个是如何测量响度,一个拿什么当标准。ReplayGain作为音量规格化的一种实现,其实就是解决了这两个问题。

响度的测量

我之前一直以为,ReplayGain的响度测量其实就是单纯测量了一下音频信号的平均强度。

这里稍微赘述一下,(解码后的)音频信号其实表示起来非常简单,就俩量:一个是采样率(每秒多少个点,一般音频是44100 Hz),一个就是按照该采样间隔一字排开的一组时序的数据,每个代表当时的信号强度(当然,存储的时候这系列数据是逐个量化成一定位长的二进制)。至于强度的的范围,有多种表示方式,不过最常用的是是[-1, 1]。绝对值越大,理论上声音也就越响。其中最大的绝对值,一般叫做“Full Scale”,缩写FS。一个点的值既可以写成单纯的一个数字,也可以用dB来表示,例如如果是0.5,就可以写成-6.0206 dB relative to full scale,一般简称dBFS。这里有个计算器可以用(注意这里针对场量和功率量中dB的算法不同,这里应该用和电压、电流一样的场量的算法)。

说回“平均强度”。学过信号与处理的应该都知道(虽然我并没学过w),在这里是测量信号的方均根(Root mean square,RMS),而不是平均值或者绝对值平均。RMS这个度量,可以更好地反映比较不同音轨之间的“能量”差别。例如,一个幅值为1的正弦波的RMS就是 0.7071,这个值也可以写成dbFS的形式,这里就是-3.0103 dBFS(这个值很重要,我们后面还会遇到)。它的能量,就应该和峰值为0.7071的方波一致。同理,音乐文件多是多个波形(多为正弦波)的叠加,最简单的方法度量其“能量”的方法就是对所有的点求RMS。

公平地讲,用音频文件的RMS(物理特性)来表示响度,不算是个太坏的方式。响度和能量,两者本身就是非常相关的。不过由于人的听觉感应曲线并不是直线一根,对于不同频率的声音,敏感程度不同,还是应该有更先进的模型。“Loudness”这个词本身的含义其实就包含了人的主观感应在里面的,如果单纯讲物理特性一般会有其他的术语,这个一会再说。

ReplayGain的实现

关于ReplayGain的具体实现方式,其实在当年(2001年?)的Proposal里面讲得很清楚(这是另外一个版本,排版稍微好一点)。总体而言,分为三步:

  1. 先利用等响度曲线,通过滤镜对不同的频率部分的进行修正,给与不同的权重;
  2. 再讲音频分为每个50ms的段落,测量每段的的RMS;
  3. 将所有段落的RMS进行排序,然后选取位于95%处的RMS,作为整个音频的“代表RMS”。在这步作者的理论是,人类的感知响度其实和其中比较响的部分有关,而不是整个音轨的RMS。例如对于对话类型的音频,其中大部分时间都是空白因此总体RMS会很低,但是人只对有声音的地方敏感,所以并不会这么觉得。

最后,只要把这个代表RMS的dBFS值和标准进行比较,然后增加/减少其中的差值就行了。可以看到,整个过程很好理解,而且其本质上还是基于RMS。另外从算法中显然可见,如果放大整个音轨几个dB,其“代表RMS”也会提升对应的dB,所以要调整某个音频的响度,也非常地简单。

能量、声压、响度、RMS的关系

这里再废言几句。我们前面已经说了RMS是对音轨“平均”能量的一种度量,于是这里顺便讲讲感知响度/声压/能量的关系。说到声音大小,最常听说的说法就是“分贝”。其实准确而言,这里的分贝是dB SPL,即声压级(Sound pressure level)。我们知道dB是一个比较量,这里就是指相对于一个标准化了的基准声压,20 μPa(有时称为听阈)的dB值。声压级是个场量,所以20 dB = 10倍。而声音的能量,一般可以用声音能量密度(Sound intensity)或声功率(Sound power)(这两者之间就差了一个面积)来表示。这是另外一个不错的度量声音强度的方法。其和声压的对应关系是:声音能量密度扩大100倍,声压扩大10倍。不过由于声音能量密度和声功率都是功率量,所以如果也表示成级(Level)的话,是每扩大10倍=10 dB,或者20 dB等于变大100倍。因此,假设一个基准声音为1 [单位]的声压和1 [单位]的声音能量密度,那么一个有20 dB声压级的声音也正好会有20 dB的声音能量密度级——不过绝对数值上,分别会是10 [单位] 声压和100 [单位] 声音能量密度。

回到RMS的话,可以观察到,RMS的量纲是和波形的点的数值一致的场量(因为又开方过了),而非功率量。因此,和RMS对应的其实应该是声压级——也就是说,两个RMS差了10倍的音频,其“声压级”会差10倍(假设你的音响完全无其他损耗),“能量密度”或“功率”则其实应该是差了100倍。不过和上面一样,如果都用dB表示,数值则都是一样的,20dB。也就是说如果你整体提升一个音轨所有点的值2 dB,其RMS也会提升2dB(自己算算就知道),声压级和声能密度级也都会提升2dB。

到此为止,都是纯粹的物理量。牵扯到(感知)响度就复杂起来。说到响度,其实搜了一下相关的文献以外地少,连维基百科都说的很模糊。网上比较常见的是sengpielaudio的一系列文章([1][2]),这里也以此为基准。我们知道,人的各种感知和对应的物理强度,一般都是呈指数级关系(Stevens’ power law)。其中比较有名的是视觉(对光的敏感程度),这个话题我原来在知乎谈过一次,什么时候也可以整理一下发个blog。听觉自然也不例外,但是“指数级”的指数到底是多少呢?

一般而言,长度不过短、频率适中的声音,可以经验地认为声压级(SPL)每扩大10倍(即20dB),感知响度扩大4倍。也就是说,响度L正比于声压SP^0.6。如果换成声音能量密度,那就是L正比于SI^0.5*0.6=SI^0.3(因为声压和声能密度是开方关系)。换句话说,就是每10dB,响度翻倍(别忘了对于SI和SP,dB数是一样的)。

这里无耻地盗一张图来说明。

Loudness - Sound Pressure - Sound Intensity
响度/声压/声音能量密度对应表

Source:http://www.sengpielaudio.com/calculator-levelchange.htm

OK,既然我们知道了响度至少和能量、声压、甚至常说的dB数都不是线性而是指数关系,那么为啥我们还用RMS?仔细想想就会发现,我们的目的只有一个:使音量保持在一个水平线上。所以,不论他们之间的关系是啥,线性还是不线性,只要都是正相关的就可以:如果俩文件的RMS(或者是ReplayGain算出来的“代表RMS”)经过加减dB之后相同,那至少我们可以说,他们的响度也类似。毕竟,我们并不需要准确知道“A比B响多少”。其实就像我们说RMS是音频“能量”的代表,但也不是RMS大10倍能量就大10倍(而是100倍)。这就好比我们用摄氏度表示物体的冷热程度,你也不能说10度比1度热10倍一样(即使你换算成K,这种说法也不一定成立)。但是如果仅用来比较两者孰大孰小,就没问题。

响度的基准

现在,我们解决了第一个问题——如何测量响度。第二个问题自然就是选取标准。在当时,音响行业并没有任何相应的规范,于是RG的作者从电影行业——电影电视工程师协会(SMPTE)那里借来了一个规范:RMS是-20 dBFS的粉噪音,应该(在听众的位置上)呈现为83dB SPL。仔细解读这句话的话,你会发现它其实讲的是信号强度和实际声压的对应关系。你也可以说成“-15 dBFS的粉噪音应该呈现为88dB SPL”,关系依然不变。不过,这两个数也不能认为是任意选取的——粉噪音用-20 dBFS,是因为这个RMS级别的声音在电影、电视中比较典型,所谓“Alignment level”。“平均”强度是-20 dBFS,意味着在单侧有着20 dB的动态空间(即“headroom”)。这个强度的声音会被呈现为83dB SPL,大概也是认为83dB SPL是一个比较舒适的数值(这里有一份解读)。不过这里要注意,这个标准的本意是电影院用的,而电影院的音量,观众是不可调的,所以有一个规定的声压大小(83 dB SPL)很有意义。但是换成家庭媒体,意义就不大了:用户无论是在软件还是硬件,都有额外的Gain或者Volume可以调,这个数字并无太大意义。真正有意义的,是前半部分:-20 dBFS。

但是搞笑之处在于,ReplayGain自己觉得这个数太小(即平均音量太小),而且一般音乐也用不着这么大的headroom,于是自行加了6dB,变成-14 dbFS RMS粉噪音——作为RG的目标。那么,如果假设对应关系不变,那自然这个声音在理想的电影院环境里也就会被呈现为89 dB SPL了。这也就是你为什么会在各种地方看到,RG的目标是89 dB这种说法。但是可以看到,“89 dB”这个数字本身已经并没有任何实际意义了:在RG处理音轨的时候,纯粹是根据上面三步走,算出一个音轨的代表RMS,然后和-14 dbFS RMS的粉噪音的代表RMS比较而已。

事实上,RG1.0的原始代码都可以在这里下到,是MATLAB写的。里面也包括了一个ref_pink.wav文件,不过这还个是-20 dBFS RMS的,没有修改成-14 dBFS RMS。由于代码非常陈旧(2001年的…),MATLAB的一些函数已经发生了变化。所以,我进行了一些修改,发了个能用的版本在GitHub。对ref_pink.wav进行RG,可以看到得出的reference vRMS(前面我叫作“代表RMS”的那个东西)是-31.5。也就是说,如果是一个-14 dBFS RMS的粉噪音,就应是-25.5了。在真正的RG的实现中,无论是89/83还是-14/-20,其实都不需要参与计算,只要有这个-31.5/-25.5在就可以了。用同样的函数处理随便一个音频,得到其对应的vRMS为-14.9,也就是说我们需要降低16.6 dB,来使得其vRMS和reference(粉噪音)一致(如果换成-14 dBFS,那就是降低10.6dB)。

dBFS RMS的定义

这里又㕛叒叕得插播一段。如果你好奇地计算一下那个ref_pink.wav的RMS:

[y, Fs] = audioread(‘ref_pink.wav’);
myrms=rms(y);
valueDBFS = 20*log10(abs(myrms))

会发现……他并不是-20 dBFS,而是-23.0103 dBFS。这又是怎么回事?原来,dbFS又有“传统定义”和“数学定义”之分。所谓数学定义,就是我们这里计算的。但是在音响业中,经常用另外一种传统定义:因为音频大多是正弦波的叠加,故所谓的Full scale并无法达到。真正能达到的(在不发生削波的前提下),是一个幅值为1的正弦波的RMS,也就是0.7071。是不是觉得眼熟?前面出现过。这个数字换算成相对于数学上的Full sacle(通过方波可以达到),就刚好是-3.0103 dB。所以,经常情况下,业内说的“Full scale”,或者dBFS,是以这个值作为基准(0 dB)的。因此,一个数学上是-23.0103 dBFS的音频,在传统定义下,就变成了-20 dBFS了。这个定义一般只用于讨论RMS,在讨论波形上某个点、或者峰值时,FS依然是以1为基准。

ReplayGain——实战篇

OK,在彻底厘清了ReplayGain的今生前世,和相关的一些容易混淆的概念,我们终于可以进入实际应用,以及其中会遇到的问题——这也正是我要写此文的初衷。

响度竞赛

前面说过RG的目的是音量规格化,那就么具体到音乐,其问题来自于从90年代开始的“响度竞赛”。简单来说,商业公司发现,如果一个音轨明显比别人音量大,观众会心理上觉得更好听。因此,混音业开始悄悄地渐渐提升音频的响度,以求和别人一起放时“更突出”。

要提升响度,第一步自然是“maximize”——也就是把增益整个音频直到峰值(peak)达到1(或者0 dBFS)。不过要知道,几乎所有的商业混音本身就已经这么做了,那自然就没有上升空间。要进一步提高响度,唯有压缩动态范围——从而可以得到更高的平均响度(RMS)。因此,响度竞赛最大的影响其实并不只是响度增加,而是歌曲的动态范围也减小,起伏变小了(这里有一篇蛮长的文章,认为响度竞赛并没有导致动态范围减少。我没细看,不过在RMS level和峰值的差值这个语境下,动态范围变小是不争的事实)。

举例而言,おニャン子クラブ在1985年发行的专辑《KICK OFF》,随便选取一轨“真赤な自転車”,其RMS分别是(左右声道)[-19.6993  -20.3342](此处为“数学定义的”RMS,下同);如果拿它去跑ReplayGain,结果是-3.7319 dB(-14 dBFS粉噪音为基准,下同)。至于其峰值,是0.918945(或-0.7342 dBFS),甚至都没有max’d out(不过整张专辑的峰值确实是1就是了),单边动态范围约是19dB左右。

而前年发售的“ときめきポポロン♪”,RMS是[-11.5458  -11.5820],足足比上面的大了快9dB!峰值是1,也就是说从RMS到峰值的单边动态范围,只有11dB。如果拿这个去跑RG,算出来需要降低9.7776 dB。

在foobar2000中使用ReplayGain

可以看到,如果要想平衡所有的音量,最简单的办法当然全部都跑一遍RG,那自然也就都均衡了。不过这有俩问题:

  1. 跑所有的音乐实在是太不现实了。我本地的音乐足足有8 week+长,全部都跑一边的话大概要累死,而且这个计算其实还是挺慢的。
  2. 从上面的计算可以看到,RG默认的reference,实在是响度太低了。连以今天的标准来说声音小到不行的“真赤な自転車”,居然计算出来的是-3.7 dB,也就是还要再小3.7 dB!虽然我们可以通过其他途径再对结果进行增益,例如音量滑块或者音响的音量旋钮,但是这样的话就很难掌握foobar2000和其他程序相互的音量差。

然而,foobar2000内置的增益的目标响度是不可调的[*]。因此,我想到一种折衷的方法,利用foobar2000带的pre-amp选项。Pre-amp是一个RG之外的额外选项,可以在RG之后再加减一个dB,可以分别给有RG信息的音轨和无RG信息的音轨的设置不同的数值。我先选取大量近年的音乐,也就是音量合适不会太小、不用调整的音乐,然后全部视为一个整体进行RG计算。算出来的结果,大约是-9.5 dB。也就是说,近年的音乐的vRMS比RG的基准,平均来说高了9.5 dB。我们这里记住这个数,但是取消不保存,因为这些音乐并不需要任何处理。相反,对于那些音量偏小的老CD,我们先去真的跑RG:跑完之后的结果自然是一个一致、但是较低的音量。不过,我们只需要在pre-amp里设为+9.5 dB,所有的音乐就一样响了。而且,因为老CD毕竟是少数,这样也不用跑太多次。

[*] Foobar2000的RG的目标(-18 LUFS)是不能调的。在选项的高级里,确实倒有个选项可以设target volume level (dB)(默认89,呃至于这个数字怎么来的前面说了,这里你就理解为你修改后的数值和89的差值加到那个-18 LUFS就是),但是那个只对文件转换有用,对播放器内播放没用。

Clipping 和 True peak

和所有的增益有关的东西都需要注意一个点,就是clipping(削波)。我们知道信号的极限就是0 dBFS,如果你通过上述的RG+pre-amp之后,峰值超过了0,那就会被削波——这是我们不愿意看到的。事实上,前面也说了,80年代的音乐虽然RMS很低,但是峰值依然也是接近1的(毕竟,几乎所有的商业CD,出厂前都会max’d out)。经过我们上面的RG+pre-amp的处理,很容易地就超过了1。例如,“真赤な自転車”的峰值是-0.7342 dB,加上RG的-3.7 dB,和pre-amp的+9.5 dB,峰值就变成了+5.1 dB。这也是为什么RG同时也会扫描并且在元数据里记录峰值,便于事后再降低(fb2k里有选项)来防止clipping的缘故。

虽说一般而言,对少数峰值的削波,人耳并不敏感,不过还是尽量要避免这种情况。但是别忘了,在音频输出到mixer之前,还要经过“音量”的计算。一般而言,我的音量都设在-10到-20 dB之间,因此理论上来讲,应该不会有任何削波的问题。

呃,其实说到峰值和削波,还得插播一段讲讲true peak的问题。如果把数字形式的音乐(即一串数字)还原成模拟信号,相当于从一堆离散的采样点还原出波形。根据采样定理,在遵守原始的频带限制(频率不超过采样频率的一半)下,每一组离散点只能还原出唯一的波形信号(注:非科班出身的弊端又体现了,我原来一直没能真正理解采样定理。直到今天听到这句把常见说法“2倍于信号的频率采样可以完美采样”反过来的说法才豁然开朗。推荐看Xiph.org的这个视频,说的非常清楚,是科普的典范)。但是,能完美还原波形,不代表波形中的峰值就在我们的采样点中会出现(所以我上面说信号的极限就是0 dBFS也不太准确):

modified signal with ripple
曲线是过采样点的唯一的波形,但是峰值高于采样点

Source: https://techblog.izotope.com/2015/08/24/true-peak-detection/

因此,如果我们仅仅测试采样点的数值,来选取peak,可能会相差甚远。因此,更高级的峰值检测,一般会把信号还原之后再过采样2x甚至4x,从而来找到更准确的峰值。foobar2000的RG也自带oversample factor的选项,在advanced里的tools里。至于这个峰值搞这么准确到底有什么用(毕竟,我们的采样点本身并没有溢出嘛),就要牵扯到DAC了,这里就不赘述。

Windows mixer 的隐藏 Limiter 问题

不过,理论和实践总是不一样的。在我用上述方案播放音乐时,每当放到那些经过RG+pre-amp的老歌的大动态区域,总有一种很奇怪的感觉——嗯对,就是像被动态压缩过一样,听起来非常不适。百思不得其解之下,我决定把某首歌的RG和pre-amp硬编码进去(也就是说,彻底地修改波形,合成进去RG和pre-amp。RG本身则只是通过元数据的方法,并不真的修改波形文件本身)。虽然这样自然也会产生削波了,不过播放时的最终输出响度应该和有RG tag的原始文件一致。那么,现在播放这俩文件(原始文件+RG tag+re-amp)和转码后的文件,我惊奇地发现,听上去响度居然不一致:原始文件+RG+pre-amp的组合,要明显的小很多。

在实在没有思路的情况下,我斗胆去Fb2k的论坛发了一贴(要知道这种论坛,一般大牛脾气都不好)。不过惊喜地是,居然得到了答案。

原来,Windows的默认音频输出(Direct Sound,DS)混音器,有一个内置的“Limiter”。当输出音频超过一定值(这个值具体是多少不清楚,一说是0 dBFS)时,Windows会自行降低响度来防止削波。至于降低的方式不明,不过从我的感觉上来讲,不是整体降低音量,应该是类似于动态压缩的方式,即在一定的buffer内遇到超过1的峰值就降低,算法不是很高级从而产生不适感。

前面说过,考虑了音量之后明明根本不会超过0 dBFS才对。但是Foobar2000现在是用Windows自带的mixer来处理音量的(你改fb2k的音量,会发现右下角音量控制里面的foobar程序的音量也会跟着改),结果这个Limiter作用的时间早于音量(会检测音量调整前的峰值),结果就导致了这个现象。至于我自己压制的那个对比的文件,因为溢出的部分已经削波削掉了,自然就不会被Windows限制。不过,这个(limiter作用于音量前的问题)似乎是个Windows的bug:只有Win 7或者Win 8.1会有这个问题,在Win 10中,已经得到修复。另外,如果使用WASAPI之类的输出绕过DS,就完全不会触发这个Limiter,无论你真的溢出了没。

既然知道了原理,那解决方案也很显然了:我把所有没有RG信息的pre-amp设成-9.5 dB,有RG的设为0 dB,就可以保证两者依然均衡;但是总体音量偏小的问题,则只能通过把foobar的音量提升到0到-10 dB,还好之前留的余量足。其实,我也试过有RG信息的设成+3 dB(另外一个对应设成-6.5 dB),好像也不会被限制(虽然明明有少许溢出0 dbFS的peak),这就搞不明白了。

不过,往移动设备上转换的时候,我依然用的是新音乐原封不动、老音乐硬编码进RG+9.5 dB的方式。否则用我的解决方案播放转换过的文件,音量反而会变小了。虽然这样做可能会导致削波(因为转换时自然不会考虑音量进去),不过移动设备听不太出来。更好的方案应该是再加一层DSP,用fb2k自带的Advanced Limiter,把超过的部分智能地调整到0 dBFS以内;虽然有点像动态压缩,但是算法更高级,完全没有一般动态压缩的不适感。

顺便一提,根据某个帖子的说法,一般动态压缩的不适感似乎是来源于压缩“释放”得不够快,或者开始得太早的缘故:例如,你有一个音轨一直是很小声突然一个巨响,然后又恢复到很小声。我们想要压缩的自然是这个巨响,但是一般的动态压缩在检测到巨响(会有一个buffer预先检测)之后,会释放的比较慢,从而导致后面紧接着的“小声”部分会有个从小变大的过程,听起来就很不舒适了。

ReplayGain 2.0

故事到此,似乎也就告一段落。但是别急,还有最后一个爆炸性消息:fb2k的“ReplayGain”,并不(再)是ReplayGain。或者准确地说,并不再是原始的、也就是上面提到的算法了。我也是无意发现这件事的:你把之前我提过的ref_pink.wav文件放进foobar2000跑RG,因为是个-20dBFS RMS的而后来的RG标准是-14(见前文),理论上应该跑出来+6dB对不?结果却是:+2.35 dB

这又是怎么回事?!原来在2011年,欧洲广播联盟(EBU)提出了一个新规范,EBU R128解读),其中对响度规格化进行了规范。其中提出,响度规格化的目标应为-23 LUFS。LUFS又称LKFS,是ITU-R BS.1770中详细规定的一种测量响度的算法。比起RG,这好歹是一个正儿八经的行业协会,经过多年研究得出的规范,所以很快,foobar2000就修改了RG的算法(又称RG2.0)为ITU-R BS.1770中的算法了。唯一的区别是,为了和原来的RG保持在相当的响度,又“擅自”把目标提升了一些,改成了-18 LUFS。注意这里的“相当的响度”,是基于对大量音乐分析得出的(另参见当年的各种对比),而并不是把原始的pink噪音拿来分析的;事实上,原始的pink噪音(-14 RMS dBFS版)算出来是 -15.36 LUFS,响于-18。(如果想自己测试要注意,我发现bs1770gain对单声道处理和fb2k不同,于是我手动复制了一份声道把它变成了双声道先)。民间也有很多对这个的实现,例如r128gain (后改名为 bs1770gain,毕竟讲道理,算法的部分是bs1770规定的,而不是r128)、libebur128(fb2k就是用这个实现修改而成)等。

另外,除了直接使用ReplayGain之外,fb2k论坛的版主之一kode54开发了一个DSP插件,foo_r129norm,可以即时地将音轨的音量规格化。也就是说,如果用了个这个插件,完全傻瓜化,根本不需要单独去给音轨跑RG啦。不过,考虑到转换到移动设备的需求,我暂时并没有用它。顺便,DSP的处理是在RG之后的,也就是说pre-amp的选项就没效了。你要想再在此基础上提升一个音量,得用EQ整体加个dB咯。

结语

本文断断续续写了2天,阅读了大量的资料。不过可以说是很满足的,基本中间遇到的问题都算是想通了。中间看过的帖,我尽量都用链接插入到文章中了,算是便于自己以后查找。

Chrome 字体偏淡的问题

开始这话提前得先稍微讲一下Windows字体渲染机制。

在Win Vista-7这段时间,Windows的核心渲染机制是ClearType这个RGB次像素级渲染机制。所谓次像素,就是通过exploit屏幕成像原理(同一个像素的RGB三种颜色并不是一个发光元素,而是并列的三个)来增强锐度。叫做次像素,是因为你实质上用了某个像素点A(比如某个字母中的一个像素)边上的另一个像素B的一部分(比如只用其中的R元素)来增强了像素A。当然这本质上还是俩整像素,只不过A还是纯黑,B是一个红点;但是从人眼看来,就只是增强了对比度的A(这只是个例子,具体选什么颜色,是要从感知学上出发的)。次像素级渲染除了增强对比度之外,还可以增加所谓的appreant分辨率,也是类似原理。更详细的文章可以参见维基百科

具体说来,又能分成RGB类型和灰度类型,RGB就是为了增强某种颜色,甚至可以产生其他颜色,比如这个NN放大600倍的图:

untitled-1

可以看到字虽然应该是纯黑的,但是添加了很多RGB级的杂色,缩小了看锐度就会很高,而且笔画之间也相对平滑(比起点阵字体)。

而灰度级就是负责增加锐度和平滑度的“次像素”只用灰度了,很好理解,就不上截图了。(其实我个人感觉纯灰度的平滑/锐化机制不能算“次像素”…毕竟并没有利用到“次像素”的单元。不过算是约定俗成的叫法,就姑且这么叫了。)

Windows的ClearType一直是在RGB次像素渲染这个阵营的,与之相对,苹果的OS X一直是用灰度级。RGB次像素渲染的优点是锐度可以达到更高,但是会有不自然、平滑度不够的一些问题。其实就是一个取舍。

但是,RGB次像素渲染有个特点:和像素点的排列方式有关。如果像素的排列方式变了,锐化出来的效果就非常惨。因此,在Windows控制面板里,你其实是可以设置像素的排列顺序的。那么这就牵扯到一个问题:对于方向固定的显示器还好,对于经常需要旋转的手持设备,这是一个巨大的缺点:你总不能每次用户旋转屏幕之后,就重新刷新一下渲染设置吧?这也是为什么无论是iOS还是Android,都只有灰度的次像素级渲染。

screenshot_20170122-063529
Android 7.1 的字体渲染,放大500%倍

Windows从8开始,开始走手提设备和Desktop一体化,尤其是推出了许多官方的第三方的Tablet产品。为了应对上述的旋转问题,微软又不声不响地启用了另外一套字体渲染机制——没错,就是只有灰度级的次像素渲染。至于这个机制是否还叫ClearType,我也说不清楚,不过这个不重要。下面为了区分,我们就把带RGB的叫ClearType,不带RGB的叫做Win8+新机制。

在Win 8起的Windows中,只有部分桌面应用才会默认启用ClearType;而系统UI、Metro应用、甚至包括一些微软家的桌面应用(例如IE、Edge、Office从2013起)都完全弃用了ClearType而转用Win8+新机制。所以,在研究ClearType时千万要小心,不要误用了这些程序做范例,那是完全不同的机制。

不过,大多数第三方应用,包括Chrome和Firefox,仍然使用ClearType。所以,这个不管是Win 7 还是Win 10都一样。但是,同样是ClearType,Chrome的比起Firefox一直有偏淡的问题,相信眼尖的朋友早就发现了。

这个问题不知为何在Win 8/10下的宋体上变得更为明显(不知道是渲染机制的调整所致还是微软修改了宋体,我倾向于后者),几乎已经处于无法接受的范围。(手头没Win 10,回头补个图。)

之前在bug tracker各种场合提过多次一直未能得到关注,于是后来我自己file了一个:issue 534732。可算有了一定的关注度。

不过一直没人修或者回应,直到前几个月,才有人提出:Chrome没错(和Windows字体查看器里的效果一致),错的是Firefox。我看了下他的示意图,也自己试了下,倒也没说错;确实是Chrome的和Windows字条查看器更接近。不过,这(在我个人看来)不能反驳Firefox的效果更好的事实。

直到今天,终于事情有了进展。 [email protected]细心地发现,其实Firefox偷偷调整了一个ClearType的参数——enhanced contrast。从默认的0.5调整到了1。最搞笑的是,在Firefox设置相关的代码的注释中明明默认值还说是50(或0.5),但是实际实现代码中默认值却是1。

所以事情其实就是这么简单——Firefox和Chrome两者有不同的对比度增强参数而已。这位用户也同意1的效果更好。考虑到他是chromium计划的开发者,希望在不久的将来,Chrome也能做出更改吧!