diff --git a/projects/common/src/client/java/dan200/computercraft/client/sound/SpeakerInstance.java b/projects/common/src/client/java/dan200/computercraft/client/sound/SpeakerInstance.java index 1e55362e4..cb08140f2 100644 --- a/projects/common/src/client/java/dan200/computercraft/client/sound/SpeakerInstance.java +++ b/projects/common/src/client/java/dan200/computercraft/client/sound/SpeakerInstance.java @@ -24,7 +24,7 @@ public class SpeakerInstance { SpeakerInstance() { } - private void pushAudio(EncodedAudio buffer) { + private void pushAudio(EncodedAudio buffer, float volume) { var sound = this.sound; var stream = currentStream; @@ -32,18 +32,30 @@ public class SpeakerInstance { var exhausted = stream.isEmpty(); stream.push(buffer); - // If we've got nothing left in the buffer, enqueue an additional one just in case. - if (exhausted && sound != null && sound.stream == stream && stream.channel != null && stream.executor != null) { + if (sound == null) return; + + var volumeChanged = sound.setVolume(volume); + + if ((exhausted || volumeChanged) && sound.stream == stream && stream.channel != null && stream.executor != null) { var actualStream = sound.stream; stream.executor.execute(() -> { var channel = Nullability.assertNonNull(actualStream.channel); - if (!channel.stopped()) channel.pumpBuffers(1); + if (channel.stopped()) return; + + // If we've got nothing left in the buffer, enqueue an additional one just in case. + if (exhausted) channel.pumpBuffers(1); + + // Update the attenuation if the volume has changed: SoundEngine.tickNonPaused updates the volume + // itself, but leaves the attenuation unchanged. We mirror the logic of SoundEngine.play here. + if (volumeChanged) { + channel.linearAttenuation(Math.max(volume, 1) * sound.getSound().getAttenuationDistance()); + } }); } } public void playAudio(SpeakerPosition position, float volume, EncodedAudio buffer) { - pushAudio(buffer); + pushAudio(buffer, volume); var soundManager = Minecraft.getInstance().getSoundManager(); diff --git a/projects/common/src/client/java/dan200/computercraft/client/sound/SpeakerSound.java b/projects/common/src/client/java/dan200/computercraft/client/sound/SpeakerSound.java index 44ab385f2..e55e8d542 100644 --- a/projects/common/src/client/java/dan200/computercraft/client/sound/SpeakerSound.java +++ b/projects/common/src/client/java/dan200/computercraft/client/sound/SpeakerSound.java @@ -83,4 +83,10 @@ public class SpeakerSound extends AbstractSoundInstance implements TickableSound public @Nullable AudioStream getStream() { return stream; } + + boolean setVolume(float volume) { + if (volume == this.volume) return false; + this.volume = volume; + return true; + } }