diff options
Diffstat (limited to 'src/main/java/gregtech/client')
-rw-r--r-- | src/main/java/gregtech/client/ElectricJukeboxSound.java | 95 | ||||
-rw-r--r-- | src/main/java/gregtech/client/ISeekingSound.java | 14 | ||||
-rw-r--r-- | src/main/java/gregtech/client/SeekingOggCodec.java | 98 |
3 files changed, 207 insertions, 0 deletions
diff --git a/src/main/java/gregtech/client/ElectricJukeboxSound.java b/src/main/java/gregtech/client/ElectricJukeboxSound.java new file mode 100644 index 0000000000..0ea81ab537 --- /dev/null +++ b/src/main/java/gregtech/client/ElectricJukeboxSound.java @@ -0,0 +1,95 @@ +package gregtech.client; + +import net.minecraft.client.audio.ISound; +import net.minecraft.client.audio.ITickableSound; +import net.minecraft.util.ResourceLocation; + +public class ElectricJukeboxSound implements ISound, ISeekingSound, ITickableSound { + + public final ResourceLocation soundResource; + public float volume = 1.0F; + public float pitch = 1.0F; + public float xPosition; + public float yPosition; + public float zPosition; + public boolean repeating = false; + public int repeatDelay = 0; + public ISound.AttenuationType attenuationType = AttenuationType.LINEAR; + public boolean donePlaying = false; + + public final long seekMs; + + public ElectricJukeboxSound(ResourceLocation resource, long seekMs) { + this.soundResource = resource; + this.seekMs = seekMs; + } + + public ElectricJukeboxSound(ResourceLocation soundResource, float volume, long seekMs, float xPosition, + float yPosition, float zPosition) { + this(soundResource, seekMs); + this.volume = volume; + this.xPosition = xPosition; + this.yPosition = yPosition; + this.zPosition = zPosition; + } + + @Override + public long getSeekMillisecondOffset() { + return seekMs; + } + + @Override + public ResourceLocation getPositionedSoundLocation() { + return soundResource; + } + + @Override + public boolean canRepeat() { + return repeating; + } + + @Override + public int getRepeatDelay() { + return repeatDelay; + } + + @Override + public float getVolume() { + return volume; + } + + @Override + public float getPitch() { + return pitch; + } + + @Override + public float getXPosF() { + return xPosition; + } + + @Override + public float getYPosF() { + return yPosition; + } + + @Override + public float getZPosF() { + return zPosition; + } + + @Override + public AttenuationType getAttenuationType() { + return attenuationType; + } + + @Override + public boolean isDonePlaying() { + return donePlaying; + } + + @Override + public void update() { + // no-op + } +} diff --git a/src/main/java/gregtech/client/ISeekingSound.java b/src/main/java/gregtech/client/ISeekingSound.java new file mode 100644 index 0000000000..091b56f802 --- /dev/null +++ b/src/main/java/gregtech/client/ISeekingSound.java @@ -0,0 +1,14 @@ +package gregtech.client; + +import net.minecraft.client.audio.ISound; + +/** + * Metadata on a sound object used to seek it when starting playback. + */ +public interface ISeekingSound extends ISound { + + /** + * @return The number of milliseconds to seek by. + */ + long getSeekMillisecondOffset(); +} diff --git a/src/main/java/gregtech/client/SeekingOggCodec.java b/src/main/java/gregtech/client/SeekingOggCodec.java new file mode 100644 index 0000000000..7949578f4f --- /dev/null +++ b/src/main/java/gregtech/client/SeekingOggCodec.java @@ -0,0 +1,98 @@ +package gregtech.client; + +import java.net.URL; + +import javax.sound.sampled.AudioFormat; + +import net.minecraft.util.ResourceLocation; + +import org.apache.commons.lang3.StringUtils; + +import paulscode.sound.SoundBuffer; +import paulscode.sound.codecs.CodecJOrbis; + +/** + * A somewhat hacky codec that allows starting music playback from the middle of a Ogg Vorbis file. + * Registers for URLs of the form: {@literal jar:blah/blah.jar!blah/music.ogg?seek_ms=5000&ext=.gt5oggseek} + */ +public class SeekingOggCodec extends CodecJOrbis { + + public static final String EXTENSION = "gt5oggseek"; + + private volatile boolean fullyInitialized = false; + private volatile SoundBuffer nextBuffer = null; + + /** + * Encodes the given millisecond seek amount into a URL/resource name suffix that can be appended to the sound path + * to start playing from that point onwards. + */ + public static String getEncodedSeekSuffxix(long milliseconds) { + return String.format("?seek_ms=%d&ext=." + EXTENSION, milliseconds); + } + + /** + * @return The given path with the seeking metadata stripped from the URL + */ + public static String stripSeekMetadata(String path) { + while (path.endsWith("." + EXTENSION)) { + int qMark = path.lastIndexOf('?'); + if (qMark == -1) { + break; + } + path = path.substring(0, qMark); + } + return path; + } + + /** + * Turns the input sound ResourceLocation into one that is seeked forward the given number of milliseconds + */ + public static ResourceLocation seekResource(ResourceLocation loc, long milliseconds) { + String original = loc.getResourcePath(); + original = stripSeekMetadata(original); + return new ResourceLocation(loc.getResourceDomain(), original + getEncodedSeekSuffxix(milliseconds)); + } + + @Override + public boolean initialize(URL url) { + final String textUrl = url.toString(); + final String[] queryParts = url.getQuery() + .split("&"); + long seekMs = 0; + for (String part : queryParts) { + if (!part.startsWith("seek_ms=")) { + continue; + } + part = StringUtils.removeStart(part, "seek_ms="); + seekMs = Long.parseLong(part); + } + + if (!super.initialize(url)) { + return false; + } + + final AudioFormat format = this.getAudioFormat(); + final long samplesPerS = (long) format.getSampleRate(); + final int bytesPerSample = (format.getChannels() * format.getSampleSizeInBits() / 8); + + long remainingBytes = seekMs * samplesPerS * bytesPerSample / 1000L; + + while (remainingBytes > 0) { + final SoundBuffer buf = read(); + if (buf == null || buf.audioData == null) { + return false; + } + remainingBytes -= buf.audioData.length; + } + + synchronized (this) { + fullyInitialized = true; + } + return true; + } + + @Override + public synchronized boolean initialized() { + return fullyInitialized; + } +} |