mojira.dev
MC-89848

playsound/sound engine pitch algorithm isn't working properly

When using the /playsound command to replicate musical notes, it is important that the notes are tuned correctly. However this does not appear to be the case, as sometimes notes are slightly sharp or flat when they shouldn't be.

To Reproduce:

1. Create a test world
2. Place a repeating command block, set to "always active", with the following command:

/playsound block.note.harp master @p ~ ~ ~ 1 1 1

A note should begin playing.

3. Change the command to

/playsound block.note.harp master @p ~ ~ ~ 1 1.05946309436 1

A new note will begin playing. It should be exactly 1 semitone higher, however it is off by more than 20 cents. If you actually wanted to play the note 20 cents lower, you should type

/playsound block.note.harp master @p ~ ~ ~ 1 1.04729412282 1

You may need an equal-tempered tuner to properly conduct the measurements.

Linked issues

Comments 14

I'm not sure what to make of this in all honesty 😞

Is the difference a linear thing? Can this be solved by simply multiplying by a fixed ratio?

I'm not sure. Seems random. Here is the world I was testing the tunings with, though it uses custom sounds tuned exactly C, and still is off. Perhaps it's a system issue?

I've done a bit more testing, and I've found significant differences between 1.8 and the snapshots, leading me to believe that this is a software issue. It doesn't only apply to pitches in /playsound, though; regular note blocks are also affected. Observing for the piano instrument, I noticed that in 1.8.8 the B was more in tune while in 15w44a the B♭ and C♯ were the most in tune. The F♯ was pretty good in both versions and the G,A♭,A, and E♭ were poorly tuned in both. Here is the world I was using for testing, and Here is the tuning app I was using.

Also: Here is the log file during one session of the testworld:

Completely ignored arguments: [--nativeLauncherVersion, 285]
[00:58:47] [Client thread/INFO]: Setting user: PhilosophioStone
[00:58:47] [Client thread/INFO]: (Session ID is token:fb0f1f8ce0f34c5698f508e5f0083cdc:d8ae73c8e8ee4815820717fd888bfca7)
[00:58:48] [Client thread/INFO]: LWJGL Version: 2.9.2
[00:58:49] [Client thread/INFO]: Reloading ResourceManager: Default
[00:58:49] [Client thread/WARN]: Missing sound for event: minecraft:enchant.thorns.hit
[00:58:49] [Client thread/WARN]: Missing sound for event: minecraft:entity.guardian.thorns
[00:58:49] [Client thread/WARN]: Missing sound for event: minecraft:entity.horse.eat
[00:58:49] [Client thread/WARN]: Missing sound for event: minecraft:entity.rabbit.attack
[00:58:49] [Sound Library Loader/INFO]: Starting up SoundSystem...
[00:58:49] [Thread-5/INFO]: Initializing LWJGL OpenAL
[00:58:49] [Thread-5/INFO]: (The LWJGL binding of OpenAL.  For more information, see http://www.lwjgl.org)
2015-10-30 00:58:49.699 java[90739:2238078] 00:58:49.699 WARNING:  140: This application, or a library it uses, is using the deprecated Carbon Component Manager for hosting Audio Units. Support for this will be removed in a future release. Also, this makes the host incompatible with version 3 audio units. Please transition to the API's in AudioComponent.h.
[00:58:49] [Thread-5/INFO]: OpenAL initialized.
[00:58:50] [Sound Library Loader/INFO]: Sound engine started
[00:58:51] [Client thread/INFO]: Created: 1024x512 textures-atlas
[00:58:52] [Client thread/ERROR]: ########## GL ERROR ##########
[00:58:52] [Client thread/ERROR]: @ Post startup
[00:58:52] [Client thread/ERROR]: 1281: Invalid value
[00:58:52] [Client thread/ERROR]: ########## GL ERROR ##########
[00:58:52] [Client thread/ERROR]: @ Pre render
[00:58:52] [Client thread/ERROR]: 1281: Invalid value
[00:59:17] [Server thread/INFO]: Starting integrated minecraft server version 15w44a
[00:59:17] [Server thread/INFO]: Generating keypair
[00:59:17] [Server thread/INFO]: Preparing start region for level 0
[00:59:18] [Server thread/INFO]: Changing view distance to 16, from 10
[00:59:18] [Server thread/INFO]: PhilosophioStone[local:E:e1ab8ad3] logged in with entity id 0 at (5.3707756287232575, 56.0, 9.315376549089452)
[00:59:18] [Server thread/INFO]: PhilosophioStone joined the game
[00:59:19] [Server thread/INFO]: Saving and pausing game...
[00:59:19] [Server thread/INFO]: Saving chunks for level 'Noteblock Bug Testworld'/Overworld
[00:59:19] [Server thread/INFO]: Saving chunks for level 'Noteblock Bug Testworld'/Nether
[00:59:19] [Server thread/INFO]: Saving chunks for level 'Noteblock Bug Testworld'/The End
[00:59:37] [Server thread/INFO]: Saving and pausing game...
[00:59:37] [Server thread/INFO]: Saving chunks for level 'Noteblock Bug Testworld'/Overworld
[00:59:37] [Server thread/INFO]: Saving chunks for level 'Noteblock Bug Testworld'/Nether
[00:59:37] [Server thread/INFO]: Saving chunks for level 'Noteblock Bug Testworld'/The End
[00:59:38] [Server thread/INFO]: Stopping server
[00:59:38] [Server thread/INFO]: Saving players
[00:59:38] [Server thread/INFO]: Saving worlds
[00:59:38] [Server thread/INFO]: Saving chunks for level 'Noteblock Bug Testworld'/Overworld
[00:59:38] [Server thread/INFO]: Saving chunks for level 'Noteblock Bug Testworld'/Nether
[00:59:38] [Server thread/INFO]: Saving chunks for level 'Noteblock Bug Testworld'/The End
[00:59:40] [Client thread/INFO]: Deleting level Noteblock Bug Testworld
[00:59:40] [Client thread/INFO]: Attempt 1...
[00:59:42] [Client thread/INFO]: Stopping!
[00:59:42] [Client thread/INFO]: SoundSystem shutting down...
[00:59:42] [Client thread/WARN]: Author: Paul Lamb, www.paulscode.com

Now the event name isn't note.harp anymore, it's block.note.harp (check MC-91102); might be good to change the description. 😉

4 more comments

1 semitone is a musical interval. It is what you get when you play the middle C on a piano and then play a C#. If a note has a frequency f, then the note 1 semitone higher will have a frequency of f*2^(1/12). The problem I'm getting is that when I use that double value, which is very close to 2^(1/12), as my pitch parameter, I get a note that is slightly less than 1 semitone higher; rather I get a note that is about 80 cents (a cent is 1/100 of a semitone) higher than the original frequency, or if the initial frequency is f, the resultant frequency I am getting is closer to f*2^(80/1200).

There are plenty of tuner apps for android, by the way.

So actually found what is going on.

When we send the pitch over the wire we multiply it by a constant and then when it gets off the wire, we divide again. This all so it fits in a single byte but in process this destroys accuracy on a linear scale.

The broken version:
float PITCH_ACCURACY = Byte.MAX_VALUE / 2f;

The 'working version':
float PITCH_ACCURACY = Byte.MAX_VALUE / 2;

For 1.10 I'll remove this completely and just send the raw float we have over the wire, that is far more accurate especially since pitch is not a linear scale.

Thanks! I'll be sure to test this when 1.9.3 comes out and report back.

So I tested it in 1.9.3 and it's definitely better than it was before. Some of the notes were still off when testing with noteblocks. When testing with a command block I found that

/playsound block.note.harp master @p ~ ~ ~ 1 1.05946309436 1

was still giving me a note that was about 20 cents flat. I suspect that keeping full float precision will fix this, so I'd mark it as fixed for 1.10. When it comes I'll be sure to do more testing.

yes! Tested in 1.10 and it's finally fixed! I'm curious; now that pitch is sent as floating point, are we still limited to just 1 octave? Or will that limit be lifted?

Ely G

Erik Broes

Plausible

Minecraft 15w40b, Minecraft 15w41b, Minecraft 15w43a, Minecraft 15w44a, Minecraft 15w44b, ..., Minecraft 1.9.3 Pre-Release 1, Minecraft 1.9.3 Pre-Release 2, Minecraft 1.9.3 Pre-Release 3, Minecraft 1.9.3, Minecraft 1.9.4

Minecraft 16w20a

Retrieved