Skip to content

Commit

Permalink
Fix SoundQueue:
Browse files Browse the repository at this point in the history
- Add AdaptiveOggAudioStream
- Add OggAudioStreamMixin
  • Loading branch information
FirstMegaGame4 committed Feb 1, 2025
1 parent f5f49fb commit d518d47
Show file tree
Hide file tree
Showing 6 changed files with 182 additions and 54 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.mmodding.mmodding_lib.library.sounds.client;

import com.mmodding.mmodding_lib.library.sounds.client.stream.AdaptiveOggAudioStream;
import com.mmodding.mmodding_lib.library.sounds.client.stream.ReleasableRepeatingAudioStream;
import com.mmodding.mmodding_lib.mixin.accessors.client.SoundLoaderAccessor;
import net.fabricmc.api.EnvType;
Expand All @@ -14,7 +15,6 @@
import org.quiltmc.loader.api.minecraft.ClientOnly;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
Expand All @@ -29,12 +29,20 @@ public class SoundQueue extends AbstractSoundInstance implements TickableSoundIn
private final SoundManager soundManager;
private final float volume;
private final float pitch;
private final float sampleRate;
private final AdaptiveOggAudioStream.TrackType trackType;

public SoundQueue(SoundManager soundManager, Identifier identifier, float volume, float pitch) {
this(soundManager, identifier, volume, pitch, 44100.0f, AdaptiveOggAudioStream.TrackType.STEREO);
}

public SoundQueue(SoundManager soundManager, Identifier identifier, float volume, float pitch, float sampleRate, AdaptiveOggAudioStream.TrackType trackType) {
super(identifier, SoundCategory.MASTER, SoundInstance.method_43221());
this.soundManager = soundManager;
this.volume = volume;
this.pitch = pitch;
this.sampleRate = sampleRate;
this.trackType = trackType;
}

public void addPositioned(SoundEvent soundEvent, boolean isLooping) {
Expand Down Expand Up @@ -157,33 +165,59 @@ public CompletableFuture<AudioStream> getAudioStream(SoundLoader loader, Identif

private AudioStream getInnerStream(SoundLoader loader, SoundInstance soundInstance) throws IOException {
InputStream stream = ((SoundLoaderAccessor) loader).mmodding_lib$getResourceManager().open(soundInstance.getSound().getLocation());
return soundInstance instanceof LoopingSoundInstance ? new ReleasableRepeatingAudioStream(OggAudioStream::new, stream) : new OggAudioStream(stream);
if (soundInstance instanceof LoopingSoundInstance) {
return new ReleasableRepeatingAudioStream(
inputStream -> new AdaptiveOggAudioStream(inputStream) {

@Override
public float getForcedSampleRate() {
return SoundQueue.this.sampleRate;
}

@Override
public TrackType getTrackType() {
return SoundQueue.this.trackType;
}
},
stream
);
}
else {
return new AdaptiveOggAudioStream(stream) {

@Override
public float getForcedSampleRate() {
return SoundQueue.this.sampleRate;
}

@Override
public TrackType getTrackType() {
return SoundQueue.this.trackType;
}
};
}
}

public static class SoundQueueStream implements AudioStream {

private static final AudioFormat DUMMY = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, AudioSystem.NOT_SPECIFIED, 16, 2, 4, AudioSystem.NOT_SPECIFIED, true);

private final DelegateFactory delegateFactory;
private final SoundQueue sounds;
private final AudioFormat format;
private final int bufferSize;

@Nullable
private AudioStream delegate;
private AudioFormat format;
private int bufferSize;

public SoundQueueStream(DelegateFactory delegateFactory, SoundQueue sounds) {
this.delegateFactory = delegateFactory;
this.sounds = sounds;
}

private static int getBufferSize(AudioFormat format, int time) {
return (int) (time * format.getSampleSizeInBits() / 8.0f * format.getChannels() * format.getSampleRate());
this.format = new AudioFormat(this.sounds.sampleRate, 16, this.sounds.trackType.equals(AdaptiveOggAudioStream.TrackType.STEREO) ? 2 : 1, true, false);
this.bufferSize = (int) (this.format.getSampleSizeInBits() / 8.0f * this.format.getChannels() * this.format.getSampleRate());
}

@Override
public AudioFormat getFormat() {
return this.format != null ? this.format : SoundQueueStream.DUMMY;
return this.format;
}

public boolean isEmpty() {
Expand All @@ -193,13 +227,9 @@ public boolean isEmpty() {
private void replaceDelegate() throws IOException {
if (!this.sounds.queue.isEmpty()) {
this.delegate = this.delegateFactory.create(this.sounds.queue.element());
this.format = this.delegate.getFormat();
this.bufferSize = getBufferSize(this.format, 1);
}
else {
this.delegate = null;
this.format = null;
this.bufferSize = -1;
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package com.mmodding.mmodding_lib.library.sounds.client.stream;

import com.mmodding.mmodding_lib.mixin.injectors.client.OggAudioStreamMixin;
import net.minecraft.client.sound.OggAudioStream;
import net.minecraft.util.math.MathHelper;
import org.jetbrains.annotations.ApiStatus;
import org.lwjgl.BufferUtils;

import java.io.IOException;
import java.io.InputStream;
import java.nio.FloatBuffer;

/**
* This class is combined with {@link OggAudioStreamMixin}
*/
public class AdaptiveOggAudioStream extends OggAudioStream {

private float sourceSampleRate;
private float targetSampleRate;

public AdaptiveOggAudioStream(InputStream inputStream) throws IOException {
super(inputStream);
}

public FloatBuffer resample(FloatBuffer source, float sourceRate, float targetRate) {
// Create Target Buffer
float ratio = targetRate / sourceRate;
int newLength = Math.round(source.remaining() * ratio);
FloatBuffer target = BufferUtils.createFloatBuffer(newLength);

// Use Linear Interpolation
for (int i = 0; i < newLength; i++) {
float srcIndex = i / ratio;
int index = (int) Math.floor(srcIndex);
float delta = srcIndex - index;
float sourceSample = source.get(index);
float targetSample = index + 1 < source.limit() ? source.get(index + 1) : sourceSample;
float interpolated = MathHelper.lerp(delta, sourceSample, targetSample);
target.put(interpolated);
}

target.flip();
return target;
}

@Override
protected void readChannels(FloatBuffer floatBuffer, OggAudioStream.ChannelList channels) {
if (this.sourceSampleRate != this.targetSampleRate) {
floatBuffer = this.resample(floatBuffer, this.sourceSampleRate, this.targetSampleRate);
}
if (this.getTrackType().equals(TrackType.STEREO)) {
while (floatBuffer.hasRemaining()) {
float f = floatBuffer.get();
channels.addChannel(f);
channels.addChannel(f);
}
}
else {
super.readChannels(floatBuffer, channels);
}
}

@Override
protected void readChannels(FloatBuffer leftFloatBuffer, FloatBuffer rightFloatBuffer, ChannelList channels) {
if (this.sourceSampleRate != this.targetSampleRate) {
leftFloatBuffer = this.resample(leftFloatBuffer, this.sourceSampleRate, this.targetSampleRate);
rightFloatBuffer = this.resample(rightFloatBuffer, this.sourceSampleRate, this.targetSampleRate);
}
if (this.getTrackType().equals(TrackType.MONO)) {
while (leftFloatBuffer.hasRemaining()) {
channels.addChannel((leftFloatBuffer.get() + rightFloatBuffer.get()) / 2.0f);
}
}
else {
super.readChannels(leftFloatBuffer, rightFloatBuffer, channels);
}
}

// Return Value must be a Constant
public float getForcedSampleRate() {
return 44100.0f;
}

// Return Value must be a Constant
public TrackType getTrackType() {
return TrackType.STEREO;
}

@ApiStatus.Internal
public void setSampleRates(float sourceSampleRate, float targetSampleRate) {
this.sourceSampleRate = sourceSampleRate;
this.targetSampleRate = targetSampleRate;
}

public enum TrackType {
MONO,
STEREO
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.mmodding.mmodding_lib.mixin.injectors.client;

import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.mmodding.mmodding_lib.library.sounds.client.stream.AdaptiveOggAudioStream;
import com.mmodding.mmodding_lib.library.utils.Self;
import net.minecraft.client.sound.OggAudioStream;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;

import javax.sound.sampled.AudioFormat;

@Mixin(OggAudioStream.class)
public class OggAudioStreamMixin implements Self<OggAudioStream> {

@WrapOperation(method = "<init>", at = @At(value = "NEW", target = "(FIIZZ)Ljavax/sound/sampled/AudioFormat;"))
private AudioFormat forceAdaptivity(float sampleRate, int sampleSizeInBits, int channels, boolean signed, boolean bigEndian, Operation<AudioFormat> original) {
if (this.getObject() instanceof AdaptiveOggAudioStream adaptive) { // If Adaptive
float sourceSampleRate = sampleRate;
if (adaptive.getTrackType().equals(AdaptiveOggAudioStream.TrackType.MONO) && channels == 2) { // Force Mono if Stereo
channels = 1;
}
else if (adaptive.getTrackType().equals(AdaptiveOggAudioStream.TrackType.STEREO) && channels == 1) { // Force Stereo if Mono
channels = 2;
}
if (adaptive.getForcedSampleRate() != sampleRate) { // Force New Sample Rate if Source Sample Rate is not Equal
sampleRate = adaptive.getForcedSampleRate();
}
adaptive.setSampleRates(sourceSampleRate, sampleRate); // Provide Original & New Sample Rate Information
}
return original.call(sampleRate, sampleSizeInBits, channels, signed, bigEndian);
}
}

This file was deleted.

4 changes: 4 additions & 0 deletions src/main/resources/mmodding_lib.accesswidener
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ accessible class net/minecraft/client/render/RenderPhase$TextureBase
accessible class net/minecraft/client/render/RenderPhase$Texturing
accessible class net/minecraft/client/render/RenderPhase$Transparency
accessible class net/minecraft/client/render/RenderPhase$WriteMaskState
accessible class net/minecraft/client/sound/OggAudioStream$ChannelList
accessible class net/minecraft/entity/passive/ParrotEntity$ParrotWanderGoal
accessible class net/minecraft/recipe/Ingredient$Entry
accessible class net/minecraft/recipe/Ingredient$StackEntry
Expand All @@ -30,6 +31,7 @@ extendable class net/minecraft/world/gen/chunk/NoiseChunkGenerator

accessible field net/minecraft/client/sound/RepeatingAudioStream delegate Lnet/minecraft/client/sound/AudioStream;

mutable field net/minecraft/client/sound/OggAudioStream format Ljavax/sound/sampled/AudioFormat;
mutable field net/minecraft/world/dimension/AreaHelper width I
mutable field net/minecraft/world/gen/chunk/ChunkNoiseSampler blockStateSampler Lnet/minecraft/world/gen/chunk/ChunkNoiseSampler$BlockStateSampler;

Expand All @@ -44,6 +46,8 @@ accessible method net/minecraft/recipe/Ingredient$TagEntry <init> (Lnet/minecraf
accessible method net/minecraft/world/gen/OreVeinCreator create (Lnet/minecraft/world/gen/DensityFunction;Lnet/minecraft/world/gen/DensityFunction;Lnet/minecraft/world/gen/DensityFunction;Lnet/minecraft/util/random/PositionalRandomFactory;)Lnet/minecraft/world/gen/chunk/ChunkNoiseSampler$BlockStateSampler;

extendable method net/minecraft/client/render/model/json/ItemModelGenerator createOrExpandCurrentCube (Ljava/util/List;Lnet/minecraft/client/render/model/json/ItemModelGenerator$Side;II)V
extendable method net/minecraft/client/sound/OggAudioStream readChannels (Ljava/nio/FloatBuffer;Lnet/minecraft/client/sound/OggAudioStream$ChannelList;)V
extendable method net/minecraft/client/sound/OggAudioStream readChannels (Ljava/nio/FloatBuffer;Ljava/nio/FloatBuffer;Lnet/minecraft/client/sound/OggAudioStream$ChannelList;)V
extendable method net/minecraft/text/MutableText <init> (Lnet/minecraft/text/component/TextComponent;Ljava/util/List;Lnet/minecraft/text/Style;)V
extendable method net/minecraft/world/dimension/AreaHelper getLowerCorner (Lnet/minecraft/util/math/BlockPos;)Lnet/minecraft/util/math/BlockPos;
extendable method net/minecraft/world/dimension/AreaHelper getWidth (Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/util/math/Direction;)I
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/mmodding_lib.mixins.json
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@
"injectors.client.LivingEntityRendererMixin",
"injectors.client.ModelLoaderMixin",
"injectors.client.MusicTrackerMixin",
"injectors.client.SourceMixin",
"injectors.client.OggAudioStreamMixin",
"injectors.client.StuckArrowsFeatureRendererMixin",
"injectors.client.StuckObjectsFeatureRendererMixin",
"injectors.client.TridentEntityRendererMixin",
Expand Down

0 comments on commit d518d47

Please sign in to comment.