Sounds loop/restart when exiting screens
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukebox
More generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music. It also includes any GUI closing besides the pause menu in single player – your inventory, the chat GUI, or a chest all work.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>
This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymore
For 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 1.9-pre1 appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }
When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }
Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
private List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }
(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized depending on if it's called from a separate thread, but I'm guessing not since it isn't currently needed; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 1.9-pre1's obfuscation (jd is used to decompile):
The place where resumeSounds is called in displayGuiScreen:
public void a(bfa ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bfh(); } else if ((☃ == null) && (this.h.bP() <= 0.0F)) { ☃ = new bel(null); } if (((☃ instanceof bfh)) || ((☃ instanceof bgq))) { this.u.aq = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { p(); bcw ☃ = new bcw(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aL.e(); // This is resumeAllSounds, line 890 o(); } }
Here is the code for resumeAllSounds and pauseAllSounds:
public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); } } public void f() { for (String ☃ : this.i.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } }
And here are resumeAllSounds and pauseAllSounds with the bug fixed:
List<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } pausedSounds.clear(); }
Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
Environment
All
Linked Issues
is duplicated by162
relates to6
- Fixed
[Mod] Pokechu22Trevor
[Mojang] Grum (Erik Broes)- 138
- 28
- Confirmed
- audio chest inventory jukebox loop music music-disc overlap record restart
13w42a - 1.9-pre1
13w42a 13w42b 13w43a 1.7 1.7.1 1.7.2 13w47e 13w48a 13w48b 13w49a 1.7.3 1.7.4 14w02a 14w02b 14w03b 14w04b 14w05b 14w06a 14w06b 14w07a 14w08a 1.7.5 14w10b 14w10c 14w11b 1.7.9 14w19a 14w20b 14w21a 14w21b 1.7.10-pre1 1.7.10-pre2 14w25a 14w25b 1.7.10 14w30b 14w30c 14w33c 14w34a 14w34b 14w34c 14w34d 1.8-pre1 1.8-pre2 1.8-pre3 1.8 1.8.1-pre1 1.8.1 1.8.2-pre1 1.8.2-pre2 1.8.2-pre3 1.8.2-pre4 1.8.2-pre5 1.8.2-pre6 1.8.3 1.8.4 1.8.5 1.8.6 1.8.7 1.8.8 15w31a 15w31b 15w31c 15w32a 15w32b 15w32c 15w33c 15w34a 15w34b 15w34c 15w34d 15w35b 15w35d 15w35e 15w36d 15w37a 15w38a 15w38b 15w39a 15w39b 15w39c 15w40a 15w40b 15w41b 15w42a 15w43a 15w43b 15w43c 15w44a 15w44b 15w45a 15w46a 15w47a 15w47c 15w49a 15w49b 1.8.9 15w50a 15w51a 15w51b 16w02a 16w03a 16w04a 16w05a 16w05b 16w06a 16w07a 16w07b 1.9-pre1- 1.9-pre2
Created Issue:
Jukebox music Bug
I was playing a song in a jukebox on the default resource pack, When I broke the jukebox the music stopped but then I opened up my inventory, then closed it again, and the song plays again. This works with any disc in both creative and survival mode. Did not test on multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxEnvironment
Windows 7 64 bit
is duplicated by
I was playing a song in a jukebox on the default resource pack, When I broke the jukebox the music stopped but then I opened up my inventory, then closed it again, and the song plays again. This works with any disc in both creative and survival mode. Did not test on multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukebox
From
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode).
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
I was playing a song in a jukebox on the default resource pack, When I broke the jukebox the music stopped but then I opened up my inventory, then closed it again, and the song plays again. This works with any disc in both creative and survival mode. Did not test on multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukebox
From
MC-35896:
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode).
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
is duplicated by
relates to
is duplicated by
Jukeboxmusic BugJukebox plays music after destroying the jukebox
is duplicated by
is duplicated by
relates to
is duplicated by
relates to
is duplicated by
is duplicated by
is duplicated by
Jukebox plays music after destroying the jukeboxStreaming sounds loop/start again when exiting screens
Streaming sounds loop/startagainwhen exiting screensSounds loop/restart when exiting screens
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
relates to
is duplicated by
is duplicated by
is duplicated by
relates to
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
relates to
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
relates to
is duplicated by
is duplicated by
relates to
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
is duplicated by
I was playing a song in a jukebox on the default resource pack, When I broke the jukebox the music stopped but then I opened up my inventory, then closed it again, and the song plays again. This works with any disc in both creative and survival mode.
Did not test on multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukebox
From
MC-35896:
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode).
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).I was playing a song in a jukebox on the default resource pack, When I broke the jukebox the music stopped but then I opened up my inventory, then closed it again, and the song plays again. This works with any disc in both creative and survival mode. This also occurs in multiplayer and single player.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukebox
From
MC-35896:
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
I was playing a song in a jukebox on the default resource pack, When I broke the jukebox the music stopped but then I opened up my inventory, then closed it again, and the song plays again. This works with any disc in both creative and survival mode. This also occurs in multiplayer and single player.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukebox
From
MC-35896:
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
From
MC-35896:
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
is duplicated by
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
From
MC-35896:
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply {{play}}ing it again, but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of $version appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w35b's obfuscation ([jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
azh.a, lines 835 to 864public void a(bbx ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bce(); } else if ((☃ == null) && (this.h.bv() <= 0.0F)) { ☃ = new bbi(null); } if ((☃ instanceof bce)) { this.t.ao = false; this.q.d().a(); } this.m = ☃; if (☃ != null) { o(); azu ☃ = new azu(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.r = false; } else { this.aH.e(); //This is resumeSounds; line 861. n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bvf, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bvfList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply
{{play}}ing it again, but probably the sound is getting played before it is removed.Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of
$version appearat the bottom.The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w35b's obfuscation ([jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
azh.a, lines 835 to 864public void a(bbx ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bce(); } else if ((☃ == null) && (this.h.bv() <= 0.0F)) { ☃ = new bbi(null); } if ((☃ instanceof bce)) { this.t.ao = false; this.q.d().a(); } this.m = ☃; if (☃ != null) { o(); azu ☃ = new azu(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.r = false; } else { this.aH.e(); //This is resumeSounds; line 861. n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bvf, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bvfList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w35b appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w35b's obfuscation ([jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
azh.a, lines 835 to 864public void a(bbx ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bce(); } else if ((☃ == null) && (this.h.bv() <= 0.0F)) { ☃ = new bbi(null); } if ((☃ instanceof bce)) { this.t.ao = false; this.q.d().a(); } this.m = ☃; if (☃ != null) { o(); azu ☃ = new azu(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.r = false; } else { this.aH.e(); //This is resumeSounds; line 861. n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bvf, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bvfList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w35b appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w35b's obfuscation ([jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
azh.a, lines 835 to 864public void a(bbx ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bce(); } else if ((☃ == null) && (this.h.bv() <= 0.0F)) { ☃ = new bbi(null); } if ((☃ instanceof bce)) { this.t.ao = false; this.q.d().a(); } this.m = ☃; if (☃ != null) { o(); azu ☃ = new azu(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.r = false; } else { this.aH.e(); //This is resumeSounds; line 861. n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bvf, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bvfList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w35
bappear at the bottom.The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w35b's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
azh.a, lines 835 to 864public void a(bbx☃){ if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bce(); } else if ((☃ == null) && (this.h.bv() <= 0.0F)) { ☃ = new bbi(null); } if ((☃ instanceof bce)){ this.t.ao = false; this.q.d().a(); } this.m = ☃; if (☃ != null){ o(); azu☃ = new azu(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.r = false; }else{ this.aH.e(); //This is resumeSounds;line 861.n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bvf, lines 373 to 384public void e(){ for (String ☃ : this.h.keySet()){ b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f(){ for (String ☃ : this.h.keySet()){ b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bvfList<String> pausedSounds = new ArrayList<String>(); public void e(){ for (String ☃ : this.h.keySet()){ b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃);pausedSounds.add(☃); } } public void f(){ for (String☃ :pausedSounds){ b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); }pausedSounds.clear(); }There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w35e appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w35e's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
azl.a, lines 835 to 864public void a(bcb ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bci(); } else if ((☃ == null) && (this.h.bv() <= 0.0F)) { ☃ = new bbm(null); } if ((☃ instanceof bci)) { this.t.ao = false; this.q.d().a(); } this.m = ☃; if (☃ != null) { o(); azy ☃ = new azy(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃2603, ☃); this.r = false; } else { this.aH.e(); //This is resumeSounds, line 861 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bvj, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bvfList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
is duplicated by
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w3
5eappear at the bottom.The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w35e's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
azl.a, lines 835to 864public void a(bcb☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bci(); } else if ((☃ == null) && (this.h.bv() <= 0.0F)) { ☃ = new bbm(null); } if ((☃ instanceof bci)) { this.t.ao = false; this.q.d().a(); } this.m = ☃; if (☃ != null) { o();azy☃ = newazy(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.r = false; } else { this.aH.e(); //This is resumeSounds, line 861n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bvj, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bvfList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w36d appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w36d's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
azo.a, lines 838 to 867public void a(bce ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bcl(); } else if ((☃ == null) && (this.h.bw() <= 0.0F)) { ☃ = new bbp(null); } if ((☃ instanceof bcl)) { this.t.ao = false; this.q.d().a(); } this.m = ☃; if (☃ != null) { o(); bab ☃ = new bab(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.r = false; } else { this.aH.e(); //This is resumeSounds, line 864 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bvm, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bvmList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w3
6dappear at the bottom.The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w36d's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
azo.a, lines 838to 867public void a(bce☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bcl(); } else if ((☃ == null) && (this.h.bw() <= 0.0F)) { ☃ = new bbp(null); } if ((☃ instanceof bcl)) { this.t.ao = false; this.q.d().a(); } this.m = ☃; if (☃ != null) { o(); bab☃ = new bab(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.r = false; } else { this.aH.e(); //This is resumeSounds, line 864n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bvm, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bvmList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w37a appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w37a's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bcn, lines 837 to 866public void a(bcn ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bcu(); } else if ((☃ == null) && (this.h.bw() <= 0.0F)) { ☃ = new bby(null); } if ((☃ instanceof bcu)) { this.t.ao = false; this.q.d().a(); } this.m = ☃; if (☃ != null) { o(); bak ☃ = new bak(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.r = false; } else { this.aH.e(); //This is resumeSounds, line 863. n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bvv, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bvvList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w3
7a appear at the bottom.The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w37a's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bcn, lines 837 to 866public void a(bcn☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bcu(); } else if ((☃ == null) && (this.h.bw() <= 0.0F)) { ☃ = new bby(null); } if ((☃ instanceof bcu)) { this.t.ao = false; this.q.d().a(); } this.m = ☃; if (☃ != null) { o(); bak☃ = new bak(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.r = false; } else { this.aH.e(); //This is resumeSounds, line 863.n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bvv, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bvvList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w38a appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w38a's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bab, lines 837 to 866public void a(bcr ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bcy(); } else if ((☃ == null) && (this.h.bx() <= 0.0F)) { ☃ = new bcc(null); } if ((☃ instanceof bcy)) { this.t.ao = false; this.q.d().a(); } this.m = ☃; if (☃ != null) { o(); bao ☃ = new bao(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.r = false; } else { this.aH.e(); //This is resumeSounds, line 863 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bvz, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bvzList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w38
aappear at the bottom.The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w38a's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bab, lines 837 to 866public void a(bcr ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bcy(); } else if ((☃ == null) && (this.h.bx() <= 0.0F)) { ☃ = new bcc(null); } if ((☃ instanceof bcy)) { this.t.ao = false; this.q.d().a(); } this.m = ☃; if (☃ != null) { o(); bao ☃ = new bao(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.r = false; } else { this.aH.e(); //This is resumeSounds, line 863 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bvz, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bvzList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w38b appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w38b's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bab, lines 837 to 866public void a(bcr ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bcy(); } else if ((☃ == null) && (this.h.bx() <= 0.0F)) { ☃ = new bcc(null); } if ((☃ instanceof bcy)) { this.t.ao = false; this.q.d().a(); } this.m = ☃; if (☃ != null) { o(); bao ☃ = new bao(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.r = false; } else { this.aH.e(); //This is resumeSounds, line 863 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bvz, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bvzList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w3
8b appear at the bottom.The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w38b's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bab, lines 837 to 866public void a(bcr ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bcy(); } else if ((☃ == null) && (this.h.bx() <= 0.0F)) { ☃ = new bcc(null); } if ((☃ instanceof bcy)) { this.t.ao = false; this.q.d().a(); } this.m = ☃; if (☃ != null) { o(); bao ☃ = new bao(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.r = false; } else { this.aH.e(); //This is resumeSounds, line 863 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bvz, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bvzList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w39b appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w39b's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bab, lines 837 to 866public void a(bcr ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bcy(); } else if ((☃ == null) && (this.h.by() <= 0.0F)) { ☃ = new bcc(null); } if ((☃ instanceof bcy)) { this.t.ao = false; this.q.d().a(); } this.m = ☃; if (☃ != null) { o(); bao ☃ = new bao(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.r = false; } else { this.aH.e(); //This is resumeSounds, line 863. n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bvz, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bvzList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w39
bappear at the bottom.The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w39b's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bab, lines 837 to 866public void a(bcr ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bcy(); } else if ((☃ == null) && (this.h.by() <= 0.0F)) { ☃ = new bcc(null); } if ((☃ instanceof bcy)) { this.t.ao = false; this.q.d().a(); } this.m = ☃; if (☃ != null) { o(); bao ☃ = new bao(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.r = false; } else { this.aH.e(); //This is resumeSounds, line 863. n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bvz, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bvzList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w39c appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w39c's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bab, lines 837 to 866public void a(bcr ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bcy(); } else if ((☃ == null) && (this.h.by() <= 0.0F)) { ☃ = new bcc(null); } if ((☃ instanceof bcy)) { this.t.ao = false; this.q.d().a(); } this.m = ☃; if (☃ != null) { o(); bao ☃ = new bao(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.r = false; } else { this.aH.e(); //This is resumeSounds, line 863. n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bvz, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bvzList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w39c appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w39c's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bab, lines 837 to 866public void a(bcr☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bcy(); } else if ((☃ == null) && (this.h.by() <= 0.0F)) { ☃ = new bcc(null); } if ((☃ instanceof bcy)) { this.t.ao = false; this.q.d().a(); } this.m = ☃; if (☃ != null) { o(); bao☃ = new bao(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.r = false; } else { this.aH.e(); //This is resumeSounds, line 863. n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bvz, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bvzList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w39c appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w39c's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bac, lines 837 to 866public void a(bcs ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bcz(); } else if ((☃ == null) && (this.h.by() <= 0.0F)) { ☃ = new bcd(null); } if ((☃ instanceof bcz)) { this.t.ao = false; this.q.d().a(); } this.m = ☃; if (☃ != null) { o(); bap ☃ = new bap(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.r = false; } else { this.aH.e(); //This is resumeSounds, line 863. n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bwa, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bwaList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w
39cappear at the bottom.The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w39c's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bac, lines 837to 866public void a(bcs☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bcz(); } else if ((☃ == null) && (this.h.by() <= 0.0F)) { ☃ = new bcd(null); } if ((☃ instanceof bcz)) { this.t.ao = false; this.q.d().a(); } this.m = ☃; if (☃ != null) { o(); bap☃ = new bap(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.r= false; } else { this.aH.e(); //This is resumeSounds, line 863. n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bwa, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bwaList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w41b appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w41b's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bac, lines 840 to 869public void a(bcr ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bcy(); } else if ((☃ == null) && (this.h.bG() <= 0.0F)) { ☃ = new bcc(null); } if ((☃ instanceof bcy)) { this.u.ao = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bao ☃ = new bao(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aI.e(); //This is resumeSounds, line 866. n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bwf, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bwfList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
is duplicated by
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w4
1bappear at the bottom.The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w41b's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bac, lines 840to 869public void a(bcr☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bcy(); } else if ((☃ == null) && (this.h.bG() <= 0.0F)) { ☃ = new bcc(null); } if ((☃ instanceof bcy)) { this.u.ao = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bao☃ = new bao(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aI.e(); //This is resumeSounds, line 866.n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bwf, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bwfList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w43a appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w43a's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bbm, lines 849 to 878public void a(bec ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bej(); } else if ((☃ == null) && (this.h.bG() <= 0.0F)) { ☃ = new bdn(null); } if ((☃ instanceof bej)) { this.u.ao = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bbz ☃ = new bbz(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aI.e(); //This is resumeSounds, line 875 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bxq, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bxqList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w43
aappear at the bottom.The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w43a's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bbm, lines 849 to 878public void a(bec☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bej(); } else if ((☃ == null) && (this.h.bG() <= 0.0F)) { ☃ = new bdn(null); } if ((☃ instanceof bej)) { this.u.ao= false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bbz☃ = new bbz(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aI.e(); //This is resumeSounds, line 875 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bxq, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bxqList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w43b appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w43b's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bbp, lines 849 to 878public void a(beh ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new beo(); } else if ((☃ == null) && (this.h.bG() <= 0.0F)) { ☃ = new bds(null); } if ((☃ instanceof beo)) { this.u.ap = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bcc ☃ = new bcc(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aI.e(); //This is resumeSounds, line 875 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bxv, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bxvList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w43b appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w43b's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bbp, lines 849 to 878public void a(beh☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new beo(); } else if ((☃ == null) && (this.h.bG() <= 0.0F)) { ☃ = new bds(null); } if ((☃ instanceof beo)) { this.u.ap = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bcc☃ = new bcc(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aI.e(); //This is resumeSounds, line 875 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bxv, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bxvList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w43b appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w43b's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bbt, lines 849 to 878public void a(bel ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bes(); } else if ((☃ == null) && (this.h.bG() <= 0.0F)) { ☃ = new bdw(null); } if ((☃ instanceof bes)) { this.u.ap = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bcg ☃ = new bcg(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aI.e(); //This is resumeSounds, line 875 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bxz, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bxzList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w43
bappear at the bottom.The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w43b's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bbt, lines 849 to 878public void a(bel ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bes(); } else if ((☃ == null) && (this.h.bG() <= 0.0F)) { ☃ = new bdw(null); } if ((☃ instanceof bes)) { this.u.ap = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bcg ☃ = new bcg(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aI.e(); //This is resumeSounds, line 875 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bxz, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bxzList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃2603}); this.e.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w43c appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w43c's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bbt, lines 849 to 878public void a(bel ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bes(); } else if ((☃ == null) && (this.h.bG() <= 0.0F)) { ☃ = new bdw(null); } if ((☃ instanceof bes)) { this.u.ap = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bcg ☃ = new bcg(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aI.e(); //This is resumeSounds, line 875 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bxz, lines 373 to 384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bxzList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w4
3cappear at the bottom.The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w43c's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bbt, lines 849to 878public void a(bel☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bes(); } else if ((☃ == null) && (this.h.bG() <= 0.0F)) { ☃ = new bdw(null); } if ((☃ instanceof bes)) { this.u.ap = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bcg☃ = new bcg(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aI.e(); //This is resumeSounds, line 875 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bxz, lines373to384public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); } } public void f() { for (String ☃ : this.h.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bxzList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.h.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.e.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.e.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w44b appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w44b's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bca, lines 850 to 879public void a(bes ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bez(); } else if ((☃ == null) && (this.h.bH() <= 0.0F)) { ☃ = new bed(null); } if ((☃ instanceof bez)) { this.u.ap = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bcn ☃ = new bcn(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aI.e(); //This is resumeSounds, line 875 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
byi, lines 412 to 424public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); } } public void f() { for (String ☃ : this.i.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
byiList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w44b appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w44b's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bca, lines 850 to 879public void a(bes ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bez(); } else if ((☃ == null) && (this.h.bH() <= 0.0F)) { ☃ = new bed(null); } if ((☃ instanceof bez)) { this.u.ap = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bcn ☃ = new bcn(this); int ☃ = ☃.a(); int ☃2603= ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aI.e(); //This is resumeSounds, line 875n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
byi, lines 412 to 424public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); } } public void f() { for (String ☃ : this.i.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
byiList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w44b appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w44b's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bca, lines 850 to 879public void a(bes ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bez(); } else if ((☃ == null) && (this.h.bH() <= 0.0F)) { ☃ = new bed(null); } if ((☃ instanceof bez)) { this.u.ap = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bcn ☃ = new bcn(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aI.e(); //This is resumeSounds, line 876 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
byi, lines 412 to 424public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); } } public void f() { for (String ☃ : this.i.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
byiList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
is duplicated by
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w4
4bappear at the bottom.The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w44b's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bca, lines 850 to 879public void a(bes☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bez(); } else if ((☃ == null) && (this.h.bH() <= 0.0F)) { ☃ = new bed(null); } if ((☃ instanceof bez)) { this.u.ap= false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bcn☃ = new bcn(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false;} else { this.aI.e(); //This is resumeSounds, line 876 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
byi, lines 412 to 424public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); } } public void f() { for (String ☃ : this.i.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
byiList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music. It also includes any GUI closing besides the pause menu in single player – your inventory, the chat GUI, and a chest all work.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w45a appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w45a's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bbz, lines 850 to 879public void a(bep ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bew(); } else if ((☃ == null) && (this.h.bH() <= 0.0F)) { ☃ = new bea(null); } if ((☃ instanceof bew)) { this.u.aq = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bcl ☃ = new bcl(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aI.e(); //This is resumeSounds, line 876 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
byf, lines 412 to 424public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); } } public void f() { for (String ☃ : this.i.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
byfList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
is duplicated by
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music. It also includes any GUI closing besides the pause menu in single player – your inventory, the chat GUI, and a chest all work.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w4
5a appear at the bottom.The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w45a's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bbz, lines 850 to 879public void a(bep☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bew(); } else if ((☃ == null) && (this.h.bH() <= 0.0F)) { ☃ = new bea(null); } if ((☃ instanceof bew)) { this.u.aq = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bcl☃ = new bcl(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aI.e(); //This is resumeSounds, line 876 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
byf, lines 412to 424public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); } } public void f() { for (String ☃ : this.i.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
byfList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music. It also includes any GUI closing besides the pause menu in single player – your inventory, the chat GUI, and a chest all work.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w46a appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w46a's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bby, lines 850 to 879public void a(beo ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bev(); } else if ((☃ == null) && (this.h.bH() <= 0.0F)) { ☃ = new bdz(null); } if ((☃ instanceof bev)) { this.u.aq = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bck ☃ = new bck(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aI.e(); //This is resumeSounds, line 876 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bye, lines 417 to 429public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); } } public void f() { for (String ☃ : this.i.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
byeList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
is duplicated by
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music. It also includes any GUI closing besides the pause menu in single player – your inventory, the chat GUI, and a chest all work.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w4
6a appear at the bottom.The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w46a's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bby, lines 850to 879public void a(beo☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bev(); } else if ((☃ == null) && (this.h.bH() <= 0.0F)) { ☃ = new bdz(null); } if ((☃ instanceof bev)){this.u.aq = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bck☃ = new bck(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aI.e(); //This is resumeSounds, line 876n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
bye, lines 417 to 429public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); } } public void f() { for (String ☃ : this.i.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
byeList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music. It also includes any GUI closing besides the pause menu in single player – your inventory, the chat GUI, and a chest all work.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w49a appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w49a's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bbz, lines 851 to 879public void a(bep ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bew(); } else if ((☃ == null) && (this.h.bJ() <= 0.0F)) { ☃ = new bea(null); } if (((☃ instanceof bew)) || ((☃ instanceof bgf))) { this.u.aq = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bcl ☃ = new bcl(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aI.e(); //This is resumeSounds, line 877 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
byh, lines 417 to 429public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); } } public void f() { for (String ☃ : this.i.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
byhList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music. It also includes any GUI closing besides the pause menu in single player – your inventory, the chat GUI, and a chest all work.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w49a appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w49a's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bbz, lines 851 to 879public void a(bep ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bew(); } else if ((☃ == null) && (this.h.bJ() <= 0.0F)) { ☃ = new bea(null); } if (((☃ instanceof bew)) || ((☃ instanceof bgf))) { this.u.aq = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bcl ☃ = new bcl(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aI.e(); //This is resumeSounds, line 877 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
byh, lines 417 to 429public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); } } public void f() { for (String ☃ : this.i.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
byhList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music. It also includes any GUI closing besides the pause menu in single player – your inventory, the chat GUI, and a chest all work.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w49a appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w49a's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bbz, lines 851 to 880public void a(bep ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bew(); } else if ((☃ == null) && (this.h.bJ() <= 0.0F)) { ☃ = new bea(null); } if (((☃ instanceof bew)) || ((☃ instanceof bgf))) { this.u.aq = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bcl ☃ = new bcl(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aI.e(); //This is resumeSounds, line 877 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
byh, lines 417 to 429public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); } } public void f() { for (String ☃ : this.i.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
byhList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music. It also includes any GUI closing besides the pause menu in single player – your inventory, the chat GUI, and a chest all work.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w49
aappear at the bottom.The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w49a's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bbz, lines 851 to 880public void a(bep ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bew(); } else if ((☃ == null) && (this.h.bJ() <= 0.0F)) { ☃ = new bea(null); } if (((☃ instanceof bew)) || ((☃ instanceof bgf))) { this.u.aq = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bcl ☃ = new bcl(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aI.e(); //This is resumeSounds, line 877 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
byh, lines 417 to 429public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); } } public void f() { for (String ☃ : this.i.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
byhList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music. It also includes any GUI closing besides the pause menu in single player – your inventory, the chat GUI, and a chest all work.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w49b appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w49b's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bbz, lines 851 to 880public void a(bep ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bew(); } else if ((☃ == null) && (this.h.bJ() <= 0.0F)) { ☃ = new bea(null); } if (((☃ instanceof bew)) || ((☃ instanceof bgf))) { this.u.aq = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bcl ☃ = new bcl(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aI.e(); //This is resumeSounds, line 877 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
byh, lines 417 to 429public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); } } public void f() { for (String ☃ : this.i.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
byhList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
is duplicated by
relates to
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music. It also includes any GUI closing besides the pause menu in single player – your inventory, the chat GUI,
anda chest all work.Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w
49b appear at the bottom.The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w49b's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bbz, lines 851 to 880public void a(bep☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bew(); } else if ((☃ == null) && (this.h.bJ() <= 0.0F)) { ☃ = new bea(null); } if (((☃ instanceof bew)) || ((☃ instanceof bgf))) { this.u.aq = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bcl☃ = new bcl(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aI.e(); //This is resumeSounds, line 877 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
byh, lines 417 to 429public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); } } public void f() { for (String ☃ : this.i.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
byhList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music. It also includes any GUI closing besides the pause menu in single player – your inventory, the chat GUI, or a chest all work.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 15w51b appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w51b's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bcb, lines 851 to 880public void a(ber ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bey(); } else if ((☃ == null) && (this.h.bJ() <= 0.0F)) { ☃ = new bec(null); } if (((☃ instanceof bey)) || ((☃ instanceof bgh))) { this.u.aq = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bcn ☃ = new bcn(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aI.e(); //This is resumeSounds, line 877 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
byk, lines 417 to 429public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); } } public void f() { for (String ☃ : this.i.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bykList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
is duplicated by
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music. It also includes any GUI closing besides the pause menu in single player – your inventory, the chat GUI, or a chest all work.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 1
5w51bappear at the bottom.The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 15w51b's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bcb, lines 851to 880public void a(ber☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bey(); } else if ((☃ == null) && (this.h.bJ() <= 0.0F)) { ☃ = new bec(null); } if (((☃ instanceof bey)) || ((☃ instanceof bgh))) { this.u.aq = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bcn☃ = new bcn(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃2603, ☃); this.s = false; } else { this.aI.e(); //This is resumeSounds, line 877n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
byk, lines 417to 429public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); } } public void f() { for (String ☃ : this.i.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
bykList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music. It also includes any GUI closing besides the pause menu in single player – your inventory, the chat GUI, or a chest all work.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 16w02a appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 16w02a's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bcc, lines 858 to 887public void a(bey ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bff(); } else if ((☃ == null) && (this.h.bK() <= 0.0F)) { ☃ = new bej(null); } if (((☃ instanceof bff)) || ((☃ instanceof bgo))) { this.u.aq = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bcu ☃ = new bcu(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aK.e(); //This is resumeSounds, line 884 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
byr, lines 409 to 421public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); } } public void f() { for (String ☃ : this.i.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
byrList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music. It also includes any GUI closing besides the pause menu in single player – your inventory, the chat GUI, or a chest all work.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 16w0
2a appear at the bottom.The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 16w02a's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bcc, lines 858 to 887public void a(bey ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bff(); } else if ((☃ == null) && (this.h.bK() <= 0.0F)) { ☃ = new bej(null); } if (((☃ instanceof bff)) || ((☃ instanceof bgo))) { this.u.aq = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bcu ☃ = new bcu(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aK.e(); //This is resumeSounds, line 884 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
byr, lines 409 to 421public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); } } public void f() { for (String ☃ : this.i.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
byrList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).When a jukebox playing music is broken, the music initially stops, but when I opened up my inventory then closed it again, the song plays again. This works with any disc in creative and survival, and in both single- and multiplayer.
1. Get Jukebox and disc of any kind
2. Play the disc
3. Break jukebox BEFORE song ends
4. Open your inventory
5. Close Inventory
6. Song plays without a jukeboxMore generally, sounds can replay when a GUI is closed, when they shouldn't. This includes block breaking sounds, button sounds, and music. It also includes any GUI closing besides the pause menu in single player – your inventory, the chat GUI, or a chest all work.
Debug info
I recently figured out how to get minecraft to output sound debug logs by following this wiki.vg tutorial. Using the following configuration:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" packages="net.minecraft,com.mojang"> <Appenders> <Console name="SysOut" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <filters> <MarkerFilter marker="SOUNDS" onMatch="ACCEPT" onMismatch="DENY" /> </filters> <AppenderRef ref="SysOut"/> </Root> </Loggers> </Configuration>This is what the logs look like when the bug is reproduced:
[12:18:50] [Sound Library Loader/INFO]: Sound engine started [12:19:01] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 231386e6-ecda-431b-a2e7-12f936caedb2 [12:19:02] [Client thread/DEBUG]: Removed channel 231386e6-ecda-431b-a2e7-12f936caedb2 because it's not playing anymore [12:19:06] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/menu/menu2.ogg, volume was zero. [12:19:10] [Client thread/DEBUG]: Playing sound minecraft:sounds/random/click.ogg for event minecraft:gui.button.press as channel 229f3257-5902-4b42-bcae-eee3d53ec16c [12:19:11] [Client thread/DEBUG]: Removed channel 229f3257-5902-4b42-bcae-eee3d53ec16c because it's not playing anymore [12:19:22] [Client thread/DEBUG]: Skipped playing sound minecraft:sounds/music/game/calm2.ogg, volume was zero. [12:19:37] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/stone4.ogg for event minecraft:step.stone as channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b [12:19:38] [Client thread/DEBUG]: Removed channel 07f5ef05-28e9-4d6d-8f31-d0a7df0fe69b because it's not playing anymore [12:19:38] [Client thread/DEBUG]: Playing sound minecraft:sounds/step/grass3.ogg for event minecraft:step.grass as channel 1a781d6d-ab09-425b-bb92-7f6009b42362 [12:19:39] [Client thread/DEBUG]: Removed channel 1a781d6d-ab09-425b-bb92-7f6009b42362 because it's not playing anymore [12:19:45] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel c16bccae-f170-44fc-8082-f1567ddcd783 [12:19:46] [Client thread/DEBUG]: Removed channel c16bccae-f170-44fc-8082-f1567ddcd783 because it's not playing anymore [12:19:47] [Client thread/DEBUG]: Playing sound minecraft:sounds/dig/stone1.ogg for event minecraft:dig.stone as channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Resuming channel 73f94183-6a17-4355-b356-2374cd71ed68 [12:19:48] [Client thread/DEBUG]: Removed channel 73f94183-6a17-4355-b356-2374cd71ed68 because it's not playing anymoreFor 73f94183-6a17-4355-b356-2374cd71ed68, I was mashing open/close inventory (which is how the bug is reproduced). As you can see, it's getting resumed multiple times, despite never getting paused. It only replays the sound once (since resuming the sound is simply playing it again), but probably the sound is getting played before it is removed.
Programmatic cause
Note: MCP names for Minecraft 1.8 (mcp910) are used here. Obfuscated names as of 16w03a appear at the bottom.
The reason that this bug occurs is that sounds are replayed whenever a GUI is closed. The most likely reason why sounds were replayed is that they are paused when certain GUIs open (such as the ingame pause menu) in single player. However, the sounds are played even if they were never paused (IE, they are played when any GUI is closed).
net.minecraft.client.Minecraft, lines 964 - 1005/** * Sets the argument GuiScreen as the main (topmost visible) screen. */ public void displayGuiScreen(GuiScreen guiScreenIn) { if (this.currentScreen != null) { this.currentScreen.onGuiClosed(); } if (guiScreenIn == null && this.theWorld == null) { guiScreenIn = new GuiMainMenu(); } else if (guiScreenIn == null && this.thePlayer.getHealth() <= 0.0F) { guiScreenIn = new GuiGameOver(); } if (guiScreenIn instanceof GuiMainMenu) { this.gameSettings.showDebugInfo = false; this.ingameGUI.getChatGUI().clearChatMessages(); } this.currentScreen = (GuiScreen)guiScreenIn; if (guiScreenIn != null) { this.setIngameNotInFocus(); ScaledResolution var2 = new ScaledResolution(this, this.displayWidth, this.displayHeight); int var3 = var2.getScaledWidth(); int var4 = var2.getScaledHeight(); ((GuiScreen)guiScreenIn).setWorldAndResolution(this, var3, var4); this.skipRenderWorld = false; } else { this.mcSoundHandler.resumeSounds(); this.setIngameFocus(); } }When guiScreenIn is null, mcSoundHandler.resumeSounds is called. The SoundHandler methods simply call the same methods on the SoundManager.
net.minecraft.client.audio.SoundManager, lines 467 - 495/** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } }Note that resumeAllSounds works simply by calling play on all of the currently playing sounds. This works in most cases, as calling play while a sound is currently playing doesn't do anything. However, if the sound has finished playing but has not been cleaned up yet, calling play on it will cause it to play again, from the start. This is the core cause of this bug.
The simplest way to fix it is to create a list of sounds that were paused when pauseAllSounds is called, and then only play the sounds in that list when resumeAllSounds is called (and then clear the list).
Something like this:
Replacement for code in net.minecraft.client.audio.SoundManagerprivate List<String> pausedSounds = new ArrayList<String>(); /** * Pauses all currently playing sounds */ public void pauseAllSounds() { Iterator var1 = this.playingSounds.keySet().iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Pausing channel {}", new Object[] {var2}); this.sndSystem.pause(var2); pausedSounds.add(var2); } } /** * Resumes playing all currently playing sounds (after pauseAllSounds) */ public void resumeAllSounds() { Iterator var1 = this.pausedSounds.iterator(); while (var1.hasNext()) { String var2 = (String)var1.next(); logger.debug(LOG_MARKER, "Resuming channel {}", new Object[] {var2}); this.sndSystem.play(var2); } this.pausedSounds.clear(); }(It may be necessary to make pauseAllSounds and resumeAllSounds synchronized; also, don't blame me for the ugly syntax there; that's MCP's fault)
I've tested this and found that it eliminates all of the looping sound issues, which is the main part of this bug.
Here are the code snippets from above with 16w03a's obfuscation (jd is used to decompile):The place where resumeSounds is called in displayGuiScreen:
bcc, lines 858 to 887public void a(bey ☃) { if (this.m != null) { this.m.m(); } if ((☃ == null) && (this.f == null)) { ☃ = new bff(); } else if ((☃ == null) && (this.h.bK() <= 0.0F)) { ☃ = new bej(null); } if (((☃ instanceof bff)) || ((☃ instanceof bgo))) { this.u.aq = false; this.r.d().a(); } this.m = ☃; if (☃ != null) { o(); bcu ☃ = new bcu(this); int ☃ = ☃.a(); int ☃ = ☃.b(); ☃.a(this, ☃, ☃); this.s = false; } else { this.aK.e(); //This is resumeSounds, line 884 n(); } }Here is the code for resumeAllSounds and pauseAllSounds:
byr, lines 409 to 421public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); } } public void f() { for (String ☃ : this.i.keySet()) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } }And here are resumeAllSounds and pauseAllSounds with the bug fixed:
byrList<String> pausedSounds = new ArrayList<String>(); public void e() { for (String ☃ : this.i.keySet()) { b.debug(a, "Pausing channel {}", new Object[] { ☃ }); this.f.pause(☃); pausedSounds.add(☃); } } public void f() { for (String ☃ : this.pausedSounds) { b.debug(a, "Resuming channel {}", new Object[] { ☃ }); this.f.play(☃); } pausedSounds.clear(); }Obfuscation as of earlier versions can be found here.
There are other ways it could be fixed, but this is the simplest way.
Some additional oddities with jukeboxes that aren't necessarily part of this (from
MC-35896):
a) In survival mode, ejecting a disc while breaking the jukebox block may make the jukebox music permanent (Goes off after exiting the world). (Both survival and creative mode). (separate bug?)
b) Sometimes, when destroying the jukebox block (After a) ALL music can go off (Not any music until exiting Minecraft). (Creative mode).
c) Sometimes, when playing jukebox exiting the world, jukebox music can stay on (Does not go off until exiting Minecraft). (Creative mode).
is duplicated by
is duplicated by
is duplicated by
It's still there, though MC-35714 reports being fixed for 1.7.1. Block breaking/placing and chest opening sound still replays after closing inventory window. Jukebox I do think is fixed (at least I can't replicate it).
Duplicate of MC-35714 - If you have not, please use the search function in the future, to see if your bug has already been submitted. If you could not find the original report, please comment with the keywords you searched for.
Duplicate of MC-35714 - If you have not, please use the search function in the future, to see if your bug has already been submitted. If you could not find the original report, please comment with the keywords you searched for.
Duplicate of MC-35714 - If you have not, please use the search function in the future, to see if your bug has already been submitted. If you could not find the original report, please comment with the keywords you searched for.
Duplicate of MC-35714 - If you have not, please use the search function in the future, to see if your bug has already been submitted. If you could not find the original report, please comment with the keywords you searched for.
Duplicate of MC-35714 - If you have not, please use the search function in the future, to see if your bug has already been submitted. If you could not find the original report, please comment with the keywords you searched for.
Duplicate of MC-35714 - If you have not, please use the search function in the future, to see if your bug has already been submitted. If you could not find the original report, please comment with the keywords you searched for.
Duplicate of MC-35714 - If you have not, please use the search function in the future, to see if your bug has already been submitted. If you could not find the original report, please comment with the keywords you searched for.
Please do not mark issues as private, unless your bug report is an exploit or contains information about your username or server.
Duplicate of MC-35714 - If you have not, please use the search function in the future, to see if your bug has already been submitted. If you could not find the original report, please comment with the keywords you searched for.
This looks like a duplicate of MC-35714 (note that defect covers duplicated sounds for a number of events, not just chests)
Dupe of MC-35714 which covers multiple sounds in multiple events (entering inventory, chests, etc.)
MC-35714
Please use search function before posting a new bug report.
Duplicate of Unresolved
MC-35714
If you have not, please use the search function in the future, to see if your bug has already been submitted. If you could not find the original report, please comment with the keywords you searched for.
This bug makes me think of a mixture of MC-35714 and maybe MC-36502? I've been testing the door and escape menu, and I think I do hear a door sound play again, but not the last sound used (door has an open and close sound) but it replays the one or the other. Example: I can sometimes hear door open OR close twice, and sometimes open AND close. You have to be quite quick with escape. I hope it's understandable enough. Been testing it on 1.7.3.
This report isn't very comprehensible, but if I were to guess, I'd say it's a duplicate of MC-35714.
Duplicate of Unresolved
MC-35714
If you have not, please use the search function in the future, to see if your bug has already been submitted. If you could not find the original report, please comment with the keywords you searched for.
Could this just be MC-35714, and the rain sound is doubling up for a while, because it's still playing, but also restarts? Each of the four rain sound files are only 2 seconds long.
101st duplicate of MC-35714. Please use the search function to check before posting in the future. If you could not find the original report, please comment with the keywords you searched for.
Duplicate of MC-35714 - If you have not, please use the search function in the future, to see if your bug has already been submitted. If you could not find the original report, please comment with the keywords you searched for.
@Evaldas Šalaševičius : You're confirming already resolved tickets. MC-35714 is the base ticket , but that's already confirmed for 14w06b.
Duplicate of MC-35714
If you have not, please use the search function in the future, to see if your bug has already been submitted. If you could not find the original report, please comment with the keywords you searched for.
Duplicate of MC-35714 - If you have not, please use the search function in the future, to see if your bug has already been submitted. If you could not find the original report, please comment with the keywords you searched for.
Duplicate of MC-35714 – If you have not, please use the search function in the future, to see if your bug has already been submitted. If you could not find the original report, please comment with the keywords you searched for.
Duplicate of MC-35714 – If you have not, please use the search function in the future, to see if your bug has already been submitted. If you could not find the original report, please comment with the keywords you searched for.
Duplicate of MC-35714
If you have not, please use the search function in the future, to see if your bug has already been submitted. If you could not find the original report, please comment with the keywords you searched for.
111th Duplicate of MC-35714 - If you have not, please use the search function in the future, to see if your bug has already been submitted. If you could not find the original report, please comment with the keywords you searched for.
Duplicate of MC-35714
Duplicate of MC-35714
Duplicate of MC-35714
This is a duplicate, so its been marked resolved for that reason. See the bug it duplicates (MC-35714)
Dupe of MC-35714
Dupe of MC-35714
Dupe of MC-35714
Dupe of MC-35714
Dupe of MC-35714
Dupe of MC-35714
Dupe of MC-35714
Duplicate of MC-35714
Duplicate of MC-35714
Dupe of MC-35714
Dupe of MC-35714
Dupe of MC-35714
Related to MC-35714. Also happens with Guardian lasers.
Related to MC-35714.
Dupe of MC-35714
Dupe of MC-35714
The trapped chest part is a duplicate of MC-35714 (since you are exiting a screen/GUI, it also occurs if you cause a sound to play, open inventory/chat, and close the GUI).
Not sure about the lever part though.
Duplicate of MC-35714.
Dupe of MC-35714
Could this issue be related to MC-35714 and/or MC-35856? From Bentroen's and Fenhl (Max Dominik Weber)'s comments the game is either playing the End music again, playing both at the same time, or not playing at all.
Dupe of MC-35714
Dupe of MC-35714
Dupe of MC-35714.
This issue was already reported, you've created a duplicate of MC-35714 (which is not resolved)
Dupe of MC-35714
Probably caused by MC-35714 (upon using /playsound the 2nd time you open a screen, which triggers the first sound again).
Currently Minecraft does not have an ability to pause/stop sounds (except if you open the pause menu, which comes with its own bugs MC-35714). I would recommend splitting the rain sounds into several sound files, and adding a fade-in/fade-out to them.
Also I would recommend creating a file called sounds.json (in assets/minecraft, and paste in the following:
{
"ambient.weather.rain": {
"category": "weather",
"sounds": [
"ambient/weather/rain1",
"ambient/weather/rain2",
"ambient/weather/rain3",
"ambient/weather/rain4",
"ambient/weather/rain5"
]
}
}
(basically list the sound locations in quotes, and don't put a comma on the last one). This makes sure that Minecraft plays all of the sounds (otherwise it only uses the first four). Also you don't need the empty folders if they don't contain sounds in them ![]()
Confirmed for 1.8.4, though not sure if this can be fixed (at least with the current sound engine), as there is no way to stop a sound midway (unless you press ESC, which comes with bugs such as MC-35714).
Oh, that's just MC-35714. It's unrelated.
I don't know why you are only hearing the sounds when you move, I hear them all the time. Are you sure you aren't just moving too far away to hear them? The sounds also play randomly, are you sure it wasn't just a coincidence?
Dupe of MC-35714
Duplicate of MC-35714 – If you have not, please use the search function in the future, to see if your bug has already been submitted.
Duplicate of MC-35714 – If you have not, please use the search function in the future, to see if your bug has already been submitted.
Dupe of MC-35714
Dupe of MC-35714
MC-35714 is talking about GUI screens in general, also the Command block GUI screen.
This is caused by MC-35714.
Sounds will never be duplicated with not opening chat / any gui.
Dupe of MC-35714
Duplicate of MC-35714
Fixed in 1.9-pre2 as a result of the fix of MC-35714.
Fixed in 1.9-pre2 as a result of the fix of MC-35714.
F3+S no longer reloads the sound engine; it was merged with F3+T. This may be a duplicate of MC-35714.
Can confirm. It didn't always work, but it did indeed occur.
Can
notconfirm in 13w42bI get this with every music disc, and it does not happen because of opening and closing the inventory. I simply removed the disc from the jukebox and the song stopped for a few seconds, then continued.
This is one of the most annoying bugs in minecraft in my opinion, especially together with
MC-35860.Can confirm in 13w43a. Jukebox don't stop music.
STILL OCCURRING in 1.7! Come'on Mojang, don't release partially made games like EA or Rockstar. We expect better. Just saying.
I can still replicate in 1.7.1 by breaking/placing a block or open/close a chest (
MC-36603andMC-36608).This is happening to me when placing blocks too, if I place dirt, and go into my inventory immediately to grab more, it plays again. It doesn't happen all the time.
I just want to confirm... this bug ticket is in existence not JUST for the jukebox music but also for the normal background music too right?
Windows 7, Java 1.7.0_45, Minecraft 1.7.1
I can confirm this with opening/closing chests, apparently closing it quickly triggers the opening sound.
Issue still occurs in 1.7.2
Confirmed. Issue persists in 1.7.2. Background music looping appears to be fixed and is no longer an issue, but duplicate chest sounds still persist.
Yup. I also made a video showing two Minecraft music tracks playing at the same time. I was going to post a bug report but obviously I was a good person and went and searched to see if someone else had already posted the bug.
http://www.youtube.com/watch?v=io68pyzP6s8
@Zach: The background music looping is still there in 1.7.2. I just had it happen.
Still present in the latest snapshots, currently using 13w47e.
This bug kills my ears. Actually, a different one that is similar. It's made the game unplayable.
Pretty sure this relates to a bug I'm having where bringing up a menu (like your inventory) while a sound is playing causes the sound to play again when the menu is closed.
@Djome Kinoshita
I've noticed that too; it is easies to notice when you, say, place a block then immediately open a command block. I'm pretty sure it is only single player.
Still occurs in 13w49a.
EDIT: And in 1.7.3 pre-release.
Affects 1.7.4. Unpausing the game replays the last raised sound event. It's very annoying.
It appears to be related to timing — if I pause the game just as the sound is ending, I can reliably reproduce.
I also have another bug where, if I change the time using /time set, it loops through songs for if I hadn't used /time set to change the time, and also through a new ambient music loop created by a slightly off day-night cycle. It's hard to explain in words.
@Ethan John Heims:
Try a screen recorder. (I use windows media encoder: http://www.microsoft.com/en-us/download/details.aspx?id=17792)
Or maybe the twitch streaming thing. Or something. Not quite sure what.
I have something for this bug.
You can make it play twice (first time for a few seconds, then second time fully)
If you place the music disc in and at the same time pause the game, it plays the disc for a little while.
Once you unpause, it starts again, as if you just placed it in.
Also, if you eject the disc then pause the game at the same time, it doesn't play, but once you unpause, it plays the disc as if it was still in the jukebox.
These will not yield loops, but are a quicker way of seeing these bugs (also, you can play two or more music discs at a time with the eject and pause one).
They also don't need to be ending.
Confirming in latest snapshots (14w02a) 14w02b.
NEW for SMP:
This only works if there are 2 or more people in the world. One person must have a music disc, while the other has nothing. Simply follow these steps:
1. Have the second person hold down their right-click on the jukebox
2. Have the first person place the music disc in the jukebox
3. The music disc will pop out immediately
4a. The music will play fully with no music disc inside
OR
4b. The music will play, but finish early with no disc inside
I'd like to add this bug affects mostly every event that produces sounds. Examples:
It seems there's a desynch between the event and the sound or the latter is being executed twice. The sound was supposed to be played only within the duration of the event (run, open, hit) but it's noticeable the sound is being played a tic further.
Confirmed in 14w10c
Please for the love of god update the description. I believe why this bug has never been fixed is because of the instructions. You can't duplicate this bug with those instructions so please update the description!!!!!!!!
I was really hoping this would have gotten fixed in 1.7 still, because I will be playing 1.7.x for a long time to come because of mods.
I just tried it in the 1.7.10-pre2, and it is still present :/
The problem based on in-game experiences is, that sounds play an extra time when the player opens his inventory while a sound is still playing, and then closes the inventory again pretty quickly. This often happens when browsing chests and opening and closing the inventory/chests a lot, and it gets really confusing and annoying quickly.
I recorded a short video demonstration in the just released 1.7.10-pre2: http://youtu.be/7f6X4cuPRGA
Also occurs in 14w25b: https://www.youtube.com/watch?v=hEXWj0QeY9s
Issue still persists in 14w30c.
Issue much more noticeable in latest snapshot's remote multiplayer.
14w33a:
Changing gamemodes will stop background music, and at one point there were 2 background songs playing at once (not sure how to reproduce).
Also part of this issue: Opening the Command-Block GUI freezes the game, but not the music. When exiting, the music often repeats
I have also been able to confirm this with the game chat.
confirm. everytime like i splash a potion on the ground, and then press esc, and resume and press esc again the sound resume and it is a little bit weird
Confirmed for 1.8-pre1.
Confirmed for 1.8-pre2.
Confirmed for 1.8-pre3.
Confirmed for 1.8.
At 1.8:
The same goes for every sound, and opening and closing the inventory. Breaking grass, footsteps, getting objetcs, increasing exp, etc. You break something, press E before the sound stop, and then press E again, and you hear the sound.
I can understand that it happens presing 'Esc', because of some kind of sound bug or problem pausing and replaying a sound.
But opening the inventory? Why?
The amazing and lovely misteries of Minecraft.
Why do so many people keep posting very similar comments? There is no need to keep commenting that the record sounds can be replayed, or opening and closing a chest or the inventory repeats sounds.
A mod should remove some of the older/unimportant affected versions so that the list isn't quite so long
No, it's relevant for basic record keeping. You don't need the list to be easy to read. Checking the latest affected version is easy to do.
By the way Aaron Rhodes, comments like that never help either...
@a: Exactly (both)
It is not only the inventory screen, it is the chat window as well.
@Nicholas Braden
Can we just clear this up here? This works with EVERY SINGLE GUI and EVERY SINGLE sound.
Confirmed for 1.8.1-pre1.
Confirmed for 1.8.2-pre1.
Also affects any sound played in a certain time limit before opening inventory. Even affect normal music game, if your volume is set to 0%, the music that was playing continues to play but at a lower volume, if put back the music in a 100% a music frame it's listen very strong and the initial volume is returned.
Confirmed for 1.8.2-pre2, pre3 and pre4.
Confirmed for 1.8.2-pre6 so that means it is in pre5 aswell. https://www.youtube.com/watch?v=iTYaiIlSo0E
Could the reporter or a mod edit the description, because this bug affects ALL sounds (afaik). It is not just the jukebox.
For example block breaking and placing and walking sounds and chest sounds loop when you quickly open and close your inventory after the sound started playing. It gets really confusing at times.
MC-80063confirms 1.8.4Confirmed for 1.8.5 and 1.8.6
I wonder if it could occur before the sound file is not actually over, but is silent to make it sound better (less abrupt). If there are a few frames where the sound hasn't ended yet, and the chest or your inventory is opened, it may trigger the sound again. Just a thought, and I don't mean to be annoying. I mean to be helpful.
Confirmed for 1.8.7
Alright, let me give the cause of this programmatically. It's in the displayGuiScreen method of net.minecraft.client.Minecraft (these are mcp910 mappings). Here's the code at the end of that method:
Now, the second to last line is what matters here:
this.mcSoundHandler.resumeSounds();Now, when the ingame pause menu is opened (and the game is in singleplayer and not open to lan), it pauses all current sounds, but no other GUIs do so. But it resumes sounds regardless of whether it paused them when a GUI is closed.
Now, that wouldn't be that bad, except that resumeSounds doesn't actually resume sounds.
The SoundHandler (net.minecraft.client.audio.SoundHandler)'s pauseSounds and resumeSounds just call the SoundManager (net.minecraft.client.audio.SoundManager)'s pauseAllSounds and resumeAllSounds methods respectively. But...
The code in resumeAllSounds is perfectly fine if it paused them in the first place. But if it isn't, this appears to allow it to play multiple times, if the timing is good. Otherwise, it'll just resume an already-playing sound (which is, more or less, fine, since it won't start it from the beginning again). You probably could get better info by enabling debug-level logging (which there is for the SoundManager, but I couldn't get it enabled).
I think the required timing is that you need to unpause it before updateAllSounds removes it.
The simple fix that isn't very good is to just remove the call to resumeAllSounds, which will mess up the pause menu resuming sounds. Alternatively, more thorough logic could be used to see if sounds were already paused, but I feel like this would be prone to failure. But the best solution is just to track what sounds were paused, and only resume those.
Something like this:
Or more humanly-readable (this is a guess on what it should look like if it weren't decompiled):
Hopefully this is helpful.
Also, note that this doesn't fix the jukebox being broken when the disk is inserted glitch, but it does fix the repeated block sounds when closing GUIs glitch.
EDIT: It also would make sense to have the sound pausing/resuming logic moved from Minecraft.java to the ingame pause screen GUI (IE, pausing it on open if the conditions are right and resuming it when the GUI is closed). That, combined with the pausedSounds list, would make this code much clearer. (It still won't fix the left+right click on jukebox glitches)
EDIT 2: Here's the code I referenced with the obfuscated mappings (and actual line numbers).
net.minecraft.client.Minecraft.displayGuiScreen(GuiScreen) = bsu.a(bxf), quoting lines 804 to 814.
this.mcSoundHandler.resumeSounds(); is this.aD.e() (line 812). aD is a czh.
SoundHandler.pauseSounds() is czh.a(), line 182. SoundHandler.resumeSounds() is czh.e(), line 199. Both call the corresponding methods on the f field, which is the SoundManager of type cza.
SoundManager.pauseAllSounds() is cza.e() (lines 369-372), and SoundManager.resumeAllSounds() is cza.f() (lines 376-378).
The previous fix with these mappings and line numbers:
Is this helpful?
Your solution seems very clear and easy to deploy. The jukebox issue is another problem, less important than this one (for me).
Sorry for the duplicate thread. i could not find any correct matches using the keyword "Sound"
Would the sounds of mobs/events in general restarting/stacking-and-being-louder when exiting out of the inventory, pause menu, and command block menus count as the same glitch? I'd rather ask here than make a duplicate and waste moderator's time. What I mean is that if a lot of sounds are playing, and you go into any of those menus, then exit out, they all stack on each other and can be pretty loud sometimes, and can restart long sounds like the cave warning and such.
@Wyatt Boyle
Yes.
Reproduced in 1.8.8 (both the jukebox portion and repeating audio portion).
EDIT: 1.8.8 mappings for this comment:
net.minecraft.client.Minecraft.displayGuiScreen(GuiScreen) = bsu.a(axu), quoting lines 814 to 824.
this.mcSoundHandler.resumeSounds(); is this.aH.e() (line 822). aH is a bpz.
SoundHandler.pauseSounds() is bpz.a(), line 182. SoundHandler.resumeSounds() is bpz.e(), line 199. Both call the corresponding methods on the f field, which is the SoundManager of type bpx.
SoundManager.pauseAllSounds() is bpx.e() (lines 369-372), and SoundManager.resumeAllSounds() is bpx.f() (lines 376-378).
Both portions reproduced in 15w31a.
15w31a mappings for this comment:
net.minecraft.client.Minecraft.displayGuiScreen(GuiScreen) = axc.a(azu), quoting lines 801 to 811.
this.mcSoundHandler.resumeSounds(); is this.aG.e() (line 809). aH is a bsr.
SoundHandler.pauseSounds() is bsr.a(), line 182. SoundHandler.resumeSounds() is bsr.e(), line 199. Both call the corresponding methods on the f field, which is the SoundManager of type bsp.
SoundManager.pauseAllSounds() is bsp.e() (lines 369-372), and SoundManager.resumeAllSounds() is bsp.f() (lines 376-378).
Confirmed for 15w31b.
Confirmed for 15w31c. Same obf as previous comment.
Confirmed for 15w32a.
15w32a mappings for this comment:
net.minecraft.client.Minecraft.displayGuiScreen(GuiScreen) = axz.a(bar), quoting lines 801 to 811.
this.mcSoundHandler.resumeSounds(); is this.aG.e() (line 809). aG is a bto.
SoundHandler.pauseSounds() is bto.a(), line 182. SoundHandler.resumeSounds() is bto.e(), line 199. Both call the corresponding methods on the f field, which is the SoundManager (btm).
SoundManager.pauseAllSounds() is btm.e() (lines 369-372), and SoundManager.resumeAllSounds() is btm.f() (lines 376-378).
Confirmed for 15w32b.
15w32b mappings for this comment:
net.minecraft.client.Minecraft.displayGuiScreen(GuiScreen) = ayh.a(bax), quoting lines 801 to 811.
this.mcSoundHandler.resumeSounds(); is this.aG.e() (line 809). aG is a bua.
SoundHandler.pauseSounds() is bua.a(), line 182. SoundHandler.resumeSounds() is bua.e(), line 199. Both call the corresponding methods on the f field, which is the SoundManager (bty).
SoundManager.pauseAllSounds() is bty.e() (lines 369-372), and SoundManager.resumeAllSounds() is bty.f() (lines 376-378).
Confirmed in 15w33a, 15w33b, and 15w33c. Sorry for the delay.
15w33a and 15w33b mappings for this comment:
net.minecraft.client.Minecraft.displayGuiScreen(GuiScreen) = ayt.a(bbj), quoting lines 804 to 814.
this.mcSoundHandler.resumeSounds(); is this.aH.e() (line 812). aH is a buo.
SoundHandler.pauseSounds() is buo.a(), line 182. SoundHandler.resumeSounds() is buo.e(), line 199. Both call the corresponding methods on the f field, which is the SoundManager (bum).
SoundManager.pauseAllSounds() is bum.e() (lines 369-372), and SoundManager.resumeAllSounds() is bum.f() (lines 376-378).
15w33c mappings for this comment:
net.minecraft.client.Minecraft.displayGuiScreen(GuiScreen) = ayy.a(bbo), quoting lines 806 to 816.
this.mcSoundHandler.resumeSounds(); is this.aH.e() (line 814). aH is a buu.
SoundHandler.pauseSounds() is buu.a(), line 182. SoundHandler.resumeSounds() is buu.e(), line 199. Both call the corresponding methods on the f field, which is the SoundManager (bus).
SoundManager.pauseAllSounds() is bus.e() (lines 369-372), and SoundManager.resumeAllSounds() is bus.f() (lines 376-378).
Confirmed in 15w34a.
15w34a mappings for this comment:
net.minecraft.client.Minecraft.displayGuiScreen(GuiScreen) = azc.a(bbs), quoting lines 806 to 816.
this.mcSoundHandler.resumeSounds(); is this.aH.e() (line 814). aH is a buz.
SoundHandler.pauseSounds() is buz.a(), line 182. SoundHandler.resumeSounds() is buz.e(), line 199. Both call the corresponding methods on the f field, which is the SoundManager (bux).
SoundManager.pauseAllSounds() is bux.e() (lines 369-372), and SoundManager.resumeAllSounds() is bux.f() (lines 376-378).
Giving you this ticket too, original reporter seems inactive.
Can confirm for 15w39c.
Please fix this. It's getting very irritating!
@Jordan Wontsharemylastname It should be in the effects versions list already. I probably could actually write a mod for 1.8.8 and / or snapshot versions if I wanted to (it's a relatively small change to fix it) but I've had issues getting things to recompile.
Confirmed for 15w42a. A sound also replays when executing a command just after the sound played.
Confirmed for 15w44a and 15w44b
Yep, I put 15w44b in the list of versions (plus I also updated the obfuscation info).
@Pokechu22 Yes, I'm sorry, I saw it right after I made the edit, but I thought I shouldn't edit it again, since an extra mail would be sent.
Confirmed for 15w45a
The summary should say this also happens when executing a command or talking using the chat.
@Steven W.d.V.: Done.
Confirmed for 15w47a and 15w47c
In case we need one, I've can confirm 15w51b.
This also happens with some mob sounds, notably pigs and villagers.
Affects 16w06a.
Affects 16w07a.
Affects 16w07b.
Very well described issue, I can indeed get a sound replaying but not the actual song.
The main issue seems to be that sounds can get stopped but when you pause them you should only keep track of the ACTUALLY playing sounds at that moment.
It is doing this now, this should fix this bug.
Cool thanks
I tested it, and it's indeed fixed in the pre-release 2. Awesome!