Add time-varying pitch modulation and built-in procedural glitch effects

This commit is contained in:
rardog
2026-09-24 13:29:51 +03:00
parent 2b9c376bbc
commit cd3672a274
6 changed files with 460 additions and 2 deletions
@@ -23,6 +23,7 @@ package com.example.soundmod.client.audio;
import com.example.soundmod.SoundMod;
import com.example.soundmod.common.AttenuationMode;
import com.example.soundmod.common.PitchModulationMode;
import com.example.soundmod.common.SoundSettings;
import com.example.soundmod.core.ModConfig;
import com.example.soundmod.core.SoundDebug;
@@ -235,6 +236,7 @@ public final class AudioPlaybackService {
dominantCategory = src.settings.category;
}
for (PlayingSource src : this.active.values()) {
src.elapsedTicks++;
int state = AL10.alGetSourcei((int)src.source, (int)4112);
if (SoundDebug.enabled(SoundDebug.Level.L3)) {
SoundDebug.log(SoundDebug.Level.L3, "PLAYBACK", src.sourceId, "tick state={} gainTarget={}", state, Float.valueOf(src.targetGain));
@@ -250,6 +252,7 @@ public final class AudioPlaybackService {
gain = this.applyPriorityDucking(src, gain, topPriority, dominantCategory);
AL10.alSourcef((int)src.source, (int)4106, (float)Math.max(0.0f, gain));
float pitch = src.settings.pitch;
pitch *= this.computePitchModulation(src);
if (src.settings.occlusion && src.settings.use3d && occlusionFactor < 0.999f && !"voice".equals(src.settings.category)) {
pitch *= Math.max(0.9f, 1.0f - src.settings.occlusionStrength * 0.12f);
}
@@ -261,16 +264,69 @@ public final class AudioPlaybackService {
float dopplerPitch = (float)Math.max(0.75, Math.min(1.25, 1.0 + radial * 0.04));
pitch *= dopplerPitch;
}
pitch = Math.max(0.05f, Math.min(4.0f, pitch));
AL10.alSourcef((int)src.source, (int)4099, (float)pitch);
if (src.reverbSource <= 0) continue;
float wetGain = Math.max(0.0f, gain * src.settings.reverbStrength * 0.45f);
AL10.alSourcef((int)src.reverbSource, (int)4106, (float)wetGain);
AL10.alSourcef((int)src.reverbSource, (int)4099, (float)Math.max(0.05f, Math.min(4.0f, pitch * 0.97f)));
}
for (String id : remove) {
this.stop(id);
}
}
private float computePitchModulation(PlayingSource src) {
if (src.settings.pitchMode == null || src.settings.pitchMode == PitchModulationMode.STATIC) {
return 1.0f;
}
float speed = Math.max(0.05f, src.settings.pitchModSpeed);
float depth = Math.max(0.0f, src.settings.pitchModDepth);
float t = (float) src.elapsedTicks / 20.0f;
switch (src.settings.pitchMode) {
case VIBRATO: {
float freq = speed * 5.0f;
return 1.0f + (float) Math.sin(t * freq * (2.0 * Math.PI)) * (depth * 0.4f);
}
case GLITCH: {
int stepTicks = Math.max(1, (int)(8.0f / speed));
int step = src.elapsedTicks / stepTicks;
int hash = (step * 0x1f1f1f1f) ^ (src.sourceId.hashCode() * 31);
int choice = Math.abs(hash) % 7;
float glitchFactor = 1.0f;
switch (choice) {
case 0: glitchFactor = 0.5f; break;
case 1: glitchFactor = 0.75f; break;
case 2: glitchFactor = 1.25f; break;
case 3: glitchFactor = 1.5f; break;
case 4: glitchFactor = 2.0f; break;
case 5: glitchFactor = 0.9f; break;
case 6: glitchFactor = 1.15f; break;
}
return 1.0f + (glitchFactor - 1.0f) * Math.min(1.5f, depth);
}
case TAPE_STOP: {
float progress = Math.min(1.0f, t * speed * 0.2f);
float decay = (1.0f - progress);
float factor = 1.0f - (1.0f - decay * decay) * Math.min(1.0f, depth);
return Math.max(0.1f, factor);
}
case RAMP_UP: {
float progress = t * speed * 0.25f;
return Math.min(4.0f, 1.0f + progress * depth);
}
case RANDOM_JITTER: {
float wow = (float) Math.sin(t * speed * 1.8f * Math.PI) * 0.5f;
int noiseHash = (src.elapsedTicks * 1103515245 + 12345);
float flutter = (((noiseHash >> 16) & 0x7fff) / 32767.0f - 0.5f);
return 1.0f + (wow * 0.7f + flutter * 0.3f) * (depth * 0.25f);
}
default:
return 1.0f;
}
}
private float applyFades(PlayingSource src, float gain) {
if (src.fadeInTicks > 0) {
int elapsed = src.settings.fadeInTicks - src.fadeInTicks;
@@ -596,6 +652,7 @@ public final class AudioPlaybackService {
int fadeInTicks;
int fadeOutTicks;
int reverbSource;
int elapsedTicks;
long lastLiveUpdateTick = Long.MIN_VALUE;
PlayingSource(String sourceId, int source, int buffer, BlockPos pos, SoundSettings settings, long startedAtTick) {