Add comparator output, tab-completion, soundlist/soundstopall, and OpenAL low-pass occlusion/underwater filter

This commit is contained in:
rardog
2026-09-24 13:37:01 +03:00
parent cd3672a274
commit 9bee71c98b
5 changed files with 170 additions and 5 deletions
@@ -58,6 +58,7 @@ import javazoom.jl.decoder.SampleBuffer;
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.player.ClientPlayerEntity;
import net.minecraft.entity.Entity;
import net.minecraft.tags.FluidTags;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.math.RayTraceContext;
@@ -65,6 +66,8 @@ import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.vector.Vector3d;
import org.lwjgl.BufferUtils;
import org.lwjgl.openal.AL10;
import org.lwjgl.openal.ALC10;
import org.lwjgl.openal.EXTEfx;
import org.lwjgl.stb.STBVorbis;
import org.lwjgl.stb.STBVorbisInfo;
import org.lwjgl.system.MemoryStack;
@@ -200,6 +203,14 @@ public final class AudioPlaybackService {
return;
}
SoundDebug.log(SoundDebug.Level.L2, "PLAYBACK", sourceId, "stop source={} buffer={}", src.source, src.buffer);
if (src.directFilter > 0) {
try {
AL10.alSourcei(src.source, EXTEfx.AL_DIRECT_FILTER, EXTEfx.AL_FILTER_NULL);
EXTEfx.alDeleteFilters(src.directFilter);
} catch (Throwable ignored) {
}
src.directFilter = 0;
}
AL10.alSourceStop((int)src.source);
AL10.alDeleteSources((int)src.source);
if (src.reverbSource > 0) {
@@ -209,6 +220,13 @@ public final class AudioPlaybackService {
AL10.alDeleteBuffers((int)src.buffer);
}
public synchronized void stopAll() {
ArrayList<String> all = new ArrayList<>(this.active.keySet());
for (String id : all) {
this.stop(id);
}
}
public synchronized boolean isPlaying(String sourceId) {
return this.active.containsKey(sourceId);
}
@@ -223,6 +241,7 @@ public final class AudioPlaybackService {
return;
}
Vector3d playerPos = player.position();
boolean underwater = player.isEyeInFluid(FluidTags.WATER);
ArrayList<String> remove = new ArrayList<String>();
int topPriority = Integer.MIN_VALUE;
String dominantCategory = "ambient";
@@ -248,9 +267,13 @@ public final class AudioPlaybackService {
float gain = this.computeAttenuatedGain(src, playerPos);
float occlusionFactor = this.computeOcclusionFactor(src, playerPos);
gain *= occlusionFactor;
if (underwater) {
gain *= 0.72f;
}
gain = this.applyFades(src, gain);
gain = this.applyPriorityDucking(src, gain, topPriority, dominantCategory);
AL10.alSourcef((int)src.source, (int)4106, (float)Math.max(0.0f, gain));
this.updateDirectFilter(src, occlusionFactor, underwater);
float pitch = src.settings.pitch;
pitch *= this.computePitchModulation(src);
if (src.settings.occlusion && src.settings.use3d && occlusionFactor < 0.999f && !"voice".equals(src.settings.category)) {
@@ -276,6 +299,63 @@ public final class AudioPlaybackService {
}
}
private static boolean efxSupported = false;
private static boolean efxChecked = false;
private static boolean isEfxSupported() {
if (!efxChecked) {
efxChecked = true;
try {
long context = ALC10.alcGetCurrentContext();
long device = ALC10.alcGetContextsDevice(context);
efxSupported = ALC10.alcIsExtensionPresent(device, "ALC_EXT_EFX");
} catch (Throwable t) {
efxSupported = false;
}
}
return efxSupported;
}
private void updateDirectFilter(PlayingSource src, float occlusionFactor, boolean underwater) {
if (!isEfxSupported()) {
return;
}
boolean needFilter = (src.settings.occlusion && src.settings.use3d && occlusionFactor < 0.999f) || underwater;
if (!needFilter) {
if (src.directFilter > 0) {
try {
AL10.alSourcei(src.source, EXTEfx.AL_DIRECT_FILTER, EXTEfx.AL_FILTER_NULL);
} catch (Throwable ignored) {}
}
return;
}
try {
if (src.directFilter <= 0) {
src.directFilter = EXTEfx.alGenFilters();
if (src.directFilter > 0) {
EXTEfx.alFilteri(src.directFilter, EXTEfx.AL_FILTER_TYPE, EXTEfx.AL_FILTER_LOWPASS);
}
}
if (src.directFilter > 0) {
float gainHF = 1.0f;
float gainLF = 1.0f;
if (src.settings.occlusion && src.settings.use3d && occlusionFactor < 0.999f) {
float str = Math.max(0.0f, Math.min(1.0f, src.settings.occlusionStrength));
gainHF = Math.max(0.08f, 1.0f - str * 0.82f);
}
if (underwater) {
gainHF *= 0.18f;
gainLF *= 0.75f;
}
EXTEfx.alFilterf(src.directFilter, EXTEfx.AL_LOWPASS_GAIN, gainLF);
EXTEfx.alFilterf(src.directFilter, EXTEfx.AL_LOWPASS_GAINHF, gainHF);
AL10.alSourcei(src.source, EXTEfx.AL_DIRECT_FILTER, src.directFilter);
}
} catch (Throwable ignored) {
}
}
private float computePitchModulation(PlayingSource src) {
if (src.settings.pitchMode == null || src.settings.pitchMode == PitchModulationMode.STATIC) {
return 1.0f;
@@ -653,6 +733,7 @@ public final class AudioPlaybackService {
int fadeOutTicks;
int reverbSource;
int elapsedTicks;
int directFilter;
long lastLiveUpdateTick = Long.MIN_VALUE;
PlayingSource(String sourceId, int source, int buffer, BlockPos pos, SoundSettings settings, long startedAtTick) {