A study of loudness in BMS files

![A study of loudness in BMS files](https://qiita-image-store.s3.amazonaws.com/0/80627/a279b9d0-06bf-e51f-ebd4-ece98eef3e72.png)

([Re;gats&](https://twitter.com/regats_dayo/status/747303718278696960) さんからの日本語訳はこちらです。本当にありがとうございました!
https://www.dropbox.com/s/s8hc8hw9ausqdqc/BMSの音の大きさに関する研究.docx?dl=0)

Hi! In this article, I analyzed 67 BMS files from the [GENOSIDE BMS Starter Package][GENOSIDE] to determine the trends in the loudness of songs, in terms of [ReplayGain] value. The resulting ReplayGain value, on average, is at -12.2 dB. By measuring your BMS’s loudness, and applying gain to your keysound files, so that the ReplayGain value is -12.2 dB, you can make your BMS sound as loud as most other songs in this study. Instructions [for bms-renderer][bms-renderer Instructions] (Mac / Unix) and [for BMX2WAV][BMX2WAV Instructions] are also provided in this article.


# Introduction

BMS files are mostly created by the community. Novice, amateur, experts and professionals alike can all create BMS files, and share them with the community. As a result, differences in song loudness arise. Some songs are very quiet, while some songs are very loud.

This article studies about the loudness of songs found in a sample of BMS files, specifically, those found in the [GENOSIDE BMS Starter Package][GENOSIDE].

The results from this study may be used in various applications, for example:

- BMS players can automatically analyze BMS files to normalize the loudness of every song, so that we can end [the loudness war].
- BMS authors can perform analysis on their own BMS songs, and adjust their songs so that that they are as loud as others.

[the loudness war]: https://www.youtube.com/watch?v=3Gmex_4hreQ

# Overview

1. We use [bms-renderer] to render songs into WAV format.
2. We use [wavegain] to analyze the loudness of each song.
3. We analyze the results.

![Screen Shot 2015-09-15 at 23.10.01.png](https://qiita-image-store.s3.amazonaws.com/0/80627/abdc8460-e262-87b4-82f1-406b013b1378.png)


## BMS &rarr; WAV Rendering

There are existing tools that converts BMS to WAV. [Lunatic Rave 2 has a feature](http://hitkey.nekokan.dyndns.info/cmds.htm#WAVXX-ABOUT-WAV) to convert BMS to MP3. [BMX2WAV] also exists, and is the most popular tool to do this.

However, it only supports Windows (I use a Mac). Also, they outputs as 16-bit WAV files. In 16-bit files, the sound is limited at 0 dBFS. Therefore, it is necessary to normalize the volume to avoid clipping. The original loudness information is lost.

Rendering to a 32-bit float format is more desirable because [there are no clipping in these kind of files][32-bit float]<sup>※</sup>. The original loudness is preserved.

[bms-renderer] is a small command-line script that renders BMS files into 32-bit floating-point WAV format (less than 200 lines of code as of writing). It is written in JavaScript, leveraging the [Node.js] platform. It uses [bms-js][] (the same engine used in [Bemuse]) to parse BMS files and [libsndfile] to read and write wave files. Communication between JavaScript code and libsndfile is done through the [node-ffi] module.

I used bms-renderer to render the BMS files in this study, but it is also possible to use BMX2WAV. I added the instructions further below.

[32-bit float]: http://howtomakeelectronicmusic.com/mixing-tip-use-32-bit-floating-point-format-to-avoid-clipping

> ※ Note that while 32-bit float file format doesn’t have clipping problem (samples are not limited to [-1, 1] range), you may hear clipping when you try to play that file because of the limit in your [DAC][].

[DAC]: https://en.wikipedia.org/wiki/Digital-to-analog_converter


## ReplayGain

[ReplayGain] is a standard to normalize loudness of songs (similar to Apple’s sound check).

It measures the [perceived loudness][loudness measurement] of a song. It then calculate the volume (gain) adjustment that needs to be applied to the song when it is played, so that every song plays at the same volume. This is called the “replay gain value.”

[wavegain] is a command-line tool that analyzes ReplayGain for wave files.


# The Experiment

## Songs Used

I used the songs from the [GENOSIDE BMS Starter Package][GENOSIDE] as input data for analysis. I select one BMS file from each song.

However, bms-renderer only supports keysound files that have a sample rate of 44,100 and have 2 channels. If a song contains a keysound file that does not meet this criteria, then it cannot be rendered.

In the end, these 67 BMS files are used in this study.

| # | Folder | File |
| ---:| ----------------- | ------------------ |
| 1. | [ABE3]Ereshkigal_N | ereshkigal\_A7.bme |
| 2. | [anubasu-anubasu]TIOA | 0.tioa\_7a.bms |
| 3. | [BACO]Love&justice | \_03\_flonne\_spa.bml |
| 4. | [celas]crystal-world_r | \_crystal-world\_r\_7a.bme |
| 5. | [csp]hujin_raijin | hujin\_a.bme |
| 6. | [daisan]Polis_Ruin | PR\_A.bml |
| 7. | [DCF]disco the ground | Disco the ground(A).bms |
| 8. | [est]angelic_snow | as\_a7.bme |
| 9. | [ETIA.]Love_Blood | \_3\_spa.bme |
| 10. | [ETIA.]wudaohongye | \_73.bme |
| 11. | [FALL]cosmowanderer | \_cosmowanderer.bml |
| 12. | [FALL]stillaliveinlove | \_still.bml |
| 13. | [gmtn.(witch's slave)]furioso_melodia | \_carage\_furioso\_melodia[7another].bme |
| 14. | [gmtn.]solitary_melody_remix | \_carage\_solitary\_melody\_remix\_7another.bme |
| 15. | [Grandthaw]ERIS | ERIS[A].bms |
| 16. | [Grandthaw]Flesvelka | flesvelka[A].bms |
| 17. | [Hate]duty | duty\_sp03.bme |
| 18. | [HatexRitsuxSalita]YRKG | YRKG\_0710\_SPA.bme |
| 19. | [I-sm]MooN | \_38\_13.bme |
| 20. | [incinerate]Purgatorium | rengoku[ANOTHER].bme |
| 21. | [Junk]elegante | 03\_another.bme |
| 22. | [Junk]Ling_Child | 03\_another.bme |
| 23. | [Junk]Once_in_my_life | 01\_another.bme |
| 24. | [kanone]Cross_Galaxy | crossgalaxy\_A.bms |
| 25. | [kaomirin]DoS_Maid | \_DoS\_Maid\_03\_another7.bml |
| 26. | [klamnop]lights | \_prog\_a.bme |
| 27. | [knot]cold_planet | another.bms |
| 28. | [Kucchi]yakumo | yakumo\_a.bms |
| 29. | [Lime]Ophelia | \_ophelia\_another7.bme |
| 30. | [Lime]sambaland | \_sambaland\_7normal.bme |
| 31. | [Lime]stargazer | lime\_stargazer\_7h.bme |
| 32. | [luze]dtd_emperor | dtd\_emperor\_a\_bga.bme |
| 33. | [maki]yumenikki | subcons\_a7.bme |
| 34. | [nekomirin]Durandal_radioedit | \_durandal\_radio\_02\_hyper7.bme |
| 35. | [nmk]Childie | \_A.bms |
| 36. | [nmk]Serenade | \_A.bms |
| 37. | [nora2r]Newworld | \_newworld\_spa.bme |
| 38. | [Omnipotenx]PEACE_BREAKER | \_pb\_A.bme |
| 39. | [Orange_Strophe]neps_paradox | neps\_7\_3.bme |
| 40. | [orgt]DestinySalmon_stage1 | \_stage1\_a.bme |
| 41. | [Papyrus]Papyrus | papy\_a.bml |
| 42. | [PLight]poppin'_shower | ps\_another.bme |
| 43. | [Queen P.A.L.]JULIAN | \_13 [ HARD 7 ] JULIAN.bme |
| 44. | [Ras]PrayStation | PrayStation\_7a.bme |
| 45. | [rider]freja | 03\_freja\_another.bms |
| 46. | [rilym]Black_Rainbow | 03-Black\_Rainbow-7A.bms |
| 47. | [ruby.g]candy_n_baguette | sp\_cnb\_3\_span.bml |
| 48. | [sa10]banana_man | \_7ka.bme |
| 49. | [sakuzyo]Axion | axion\_A.bms |
| 50. | [sakuzyo]Black_Lair | Black\_Lair\_A.bms |
| 51. | [sakuzyo]Vallista | vallista\_another.bms |
| 52. | [sany-on]minimal_satorin | 20100121\_703\_hard.bml |
| 53. | [Shiraishi]sinSQ | \_sinSQ\_A.bms |
| 54. | [siromaru+cranky]conflict | \_03\_conflict.bme |
| 55. | [sun3 vs EXCALIpUR BGA-Johnny]Cross breed | crossbreed(ANOTHER7).bme |
| 56. | [sun3]Messier_333 | Messier 333(ANOTHER7).bme |
| 57. | [void]Name of oath | [[24]]Name of oath[SPA].bml |
| 58. | [void]zenithalize | +074 ZENITHALIZE [SPA].bme |
| 59. | [void_feat.Salita]Act_Beloved | \_\_spa.bme |
| 60. | [wa.]morion | \_morion\_7a.bme |
| 61. | [xenothium]nutstoyou | \_nutstoyou\_7a.bms |
| 62. | [xi]ascension_to_heaven | ath\_A.bme |
| 63. | [xi]freedom_dive | dive\_h7.bme |
| 64. | [xi]halcyon | \_hal\_A.bml |
| 65. | [xi]parousia | \_parousia\_A.bme |
| 66. | [Ym1024_feat.lamie]rePrayer | rePrayer\_[7-A\_Another].bme |
| 67. | [Ym1024_feat.lamie]started | start\_[7-9\_Another].bme |


## Finding ReplayGain

The command:

```
wavegain -nc *.wav
```

analyzes all the .wav files and prints a report. [__The results can be viewed here.__](https://docs.google.com/spreadsheets/d/19cTRHi1yjcxW0540myeyMovNZjzvT8_aLPcjXC5bEPs/edit?usp=sharing)


# Results

## ReplayGain

![Screen Shot 2015-09-16 at 0.23.41.png](https://qiita-image-store.s3.amazonaws.com/0/80627/e58f7e83-e822-5fb8-92a4-e0132d488de8.png)

In this chart, you can see the trends in the amount of gain to be applied to the music file.

According to the [ReplayGain 1.0 Specification](http://wiki.hydrogenaud.io/index.php?title=ReplayGain_1.0_specification), the ReplayGain algorithm will calculate the amount of gain that needs to be applied, so that its [perceived loudness][loudness measurement] matches the loudness of pink noise at -14 dBFS. In other words, it will adjust the volume so that each song has about 14 dB of headroom.

This means that the lower is the ReplayGain value, the louder is the song. On average, the songs received a ReplayGain value of -12dB.


## Peak Volume

![Screen Shot 2015-09-16 at 0.24.10.png](https://qiita-image-store.s3.amazonaws.com/0/80627/151517ee-897a-1377-5885-65eb923a11fe.png)

As can be seen in the chart above, every song here has the peak level of more than 160%, at an average of 240%. Playing at full volume, there will be a lot of clipping.

From this chart, it seemed evident, that we don’t need to worry too much whether the BMS will sound too loud.

> __Note:__ This does not mean that they don’t clip: they do, but most of them still sound quite good.


# Application: Adjusting loudness in your BMS song

When I participated in [第12回自称無名BMS作家が物申す！], I received a comment on the BMS entry 「[Exargon]」 that the BMS version does not sound as intense as it should be.

Although this event is over, let’s try to fix it as an example for future BMS work. First, I need to find the ReplayGain value of this song.

First, I rendered the BMS file into a wave file.

```
$ bms-renderer exargon_7another.bms exargon_render.wav
```

Next, I ran WaveGain on the BMS file.

```
$ wavegain -nc exargon_render.wav
 Analyzing...

    Gain   |  Peak  | Scale | New Peak |Left DC|Right DC| Track
           |        |       |          |Offset | Offset |
 --------------------------------------------------------------
  -6.41 dB |  66036 |  0.48 |    31570 |  -51  |   -61  | exargon_render.wav
```

Notice the gain correction of __-6.41 dB__.

Even the quietest song in GENOSIDE package had a ReplayGain of -8.02 dB. This means that this song is really, really quiet!

To make it as loud as the other songs, we find the amount of gain that needs to be applied so that it matches the average value (-12.2 dB).

$$ \begin{align*} -6.41\text{ dB} - (\text{extra gain}) & = -12.2\text{ dB} \\\\ \text{extra gain} & = -6.41\text{ dB} + 12.2\text{ dB} \\\\ & = +5.79\text{ dB}  \end{align*} $$

This means __we need to apply 5.79 dB of amplification to every keysound__ to make it as loud as most songs.

How to do this depends on which audio editing program you use. As for me, I use [SoX] to apply this gain adjustment to every file at once:

```
$ for I in *.ogg
  do
  sox "$I" "../exargon_louder/$I" gain 5.79
  done
```

> __Warning:__ Be aware of clipping and audio distortion! For certain kind of songs and instruments, some clipping is fine. But for songs with lots of heavy kick drums and bass, clipping sounds very bad (unless intentional). Always test within a BMS player, and use your ears to judge, not these numbers! :smile: 


## Appendix: Instructions on Windows using BMX2WAV

You can also use BMX2WAV to render your BMS, and afterwards find the ReplayGain of your BMS song.

In the conversion settings, enable the option 「WAV が鳴り終わる前に同じ WAV が鳴った場合、前の WAV を消す」 to closely match the behavior of [multiplex WAV definition] as implemented in most BMS players.

![01_ConvertOptions.PNG](https://qiita-image-store.s3.amazonaws.com/0/80627/1f670259-5108-a2f4-fa47-cc1fd13e6e8f.png)

In the audio settings, set normalize to “Peak Normalization”

![02_Normalize.PNG](https://qiita-image-store.s3.amazonaws.com/0/80627/27ccdaeb-8e61-6319-a2db-fa9628e64a63.png)

Convert your BMS file using BMX2WAV. Take note of the amplification scale (0.496192).

![03_BMX2Wav_Result.PNG](https://qiita-image-store.s3.amazonaws.com/0/80627/e54a66f7-05a7-a99e-b2a3-aebd18bde90f.png)

Use WaveGain to find the ReplayGain of your wave file. You can download [Windows Version of WaveGain from RareWares.org][RareWares WaveGain]

![04_WaveGain.PNG](https://qiita-image-store.s3.amazonaws.com/0/80627/5124040c-cbfb-1c37-3a23-c121341cba9c.png)

Here, the ReplayGain is -0.43 dB. Take note of it.

Next, find the amount of volume adjustment applied during the normalization in BMX2WAV using this formula:

$$ \begin{align*} \text{gain in dB} = 20 \log_{10} k \end{align*} $$

Where $k$ is the value from BMX2WAV. In this example:

$$ \begin{align*} \text{gain in dB} & = 20 \log_{10} (0.496192) \\\\ & = -6.087005 \text{ dB}  \end{align*} $$

Finally, add in the value from WaveGain to obtain the actual ReplayGain:

$$ (-6.09\text{ dB}) + (-0.43\text{ dB}) = (-6.52\text{ dB}) $$

The resulting number obtained from files rendered using BMX2WAV (-6.52 dB) is very close to that obtained by bms-renderer (-6.41 dB). I have tested this with few other BMS files and the results are also very close.

To make it as loud as the other songs, we find the amount of gain that needs to be applied so that it matches the average value (-12.2 dB).

$$ \begin{align*} -6.52\text{ dB} - (\text{extra gain}) & = -12.2\text{ dB} \\\\ \text{extra gain} & = -6.52\text{ dB} + 12.2\text{ dB} \\\\ & = +5.68\text{ dB}  \end{align*} $$

This means __we need to apply 5.68 dB of amplification to every keysound__ to make it as loud as most songs.

To convert decibel value to amplification factor, use [this formula][ReplayGain loudness normalization]:

$$ \text{amplification factor} = 10^{\left(\frac{\text{gain}}{20}\right)} $$

For example:

$$ \text{amplification factor} = 10^{\left(\frac{+5.68}{20}\right)} = 10^{0.284} = 1.923 $$

This means you have to amplify by __1.923x__ to make your song loudness match the average loudness of songs in this study.


[multiplex WAV definition]: http://hitkey.nekokan.dyndns.info/cmds.htm#WAVXX-MULTIPLEX-DEFINITION

[RareWares WaveGain]: http://www.rarewares.org/others.php#wavegain

[ReplayGain loudness normalization]: http://wiki.hydrogenaud.io/index.php?title=ReplayGain_1.0_specification#Loudness_normalization

# Conclusions

This article presented a survey of the 67 BMS files and found that they are VERY LOUD. Sound clipping is not much problematic, and we found that some songs even reached a peak volume of 490%.

The methods I presented in this article is quite more complicated to do on Windows systems than on Mac/Linux systems. It would be really cool if someone could build a tool that works on Windows.

I hope that this article would be useful to BMS authors and creators of other BMS players.

# About Me

I am flicknote. I am the creator of [Bemuse], a BMS simulator that runs in your browser.

[GENOSIDE]: http://nekokan.dyndns.info/~lobsak/genoside/
[ReplayGain]: https://en.wikipedia.org/wiki/ReplayGain
[BMX2WAV]: http://childs.squares.net/program/bmx2wav/
[bms-renderer]: http://github.com/bemusic/bms-renderer
[wavegain]: https://github.com/MestreLion/wavegain
[Node.js]: http://nodejs.org/
[bms-js]: https://github.com/bemusic/bms-js
[libsndfile]: http://www.mega-nerd.com/libsndfile/
[Bemuse]: http://bemuse.ninja/
[node-ffi]: https://github.com/node-ffi/node-ffi
[ReplayGain 1.0 Specification]: http://wiki.hydrogenaud.io/index.php?title=ReplayGain_1.0_specification
[loudness measurement]: http://wiki.hydrogenaud.io/index.php?title=ReplayGain_1.0_specification#Loudness_measurement
[第12回自称無名BMS作家が物申す！]: http://www.geocities.jp/mumei12_bms/
[Exargon]: http://manbow.nothing.sh/event/event.cgi?action=More_def&num=31&event=101
[SoX]: http://sox.sourceforge.net/

[bms-renderer Instructions]: #application-adjusting-loudness-in-your-bms-song
[BMX2WAV Instructions]: #appendix-instructions-on-windows-using-bmx2wav