sounds WAV -> OPUS

This commit is contained in:
Sen 2025-03-21 13:08:55 +01:00
parent 103e4d35f5
commit 93f98f9984
11 changed files with 367 additions and 554 deletions

View file

@ -4,6 +4,11 @@ import java.io.BufferedInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ShortBuffer;
import org.lwjgl.BufferUtils;
import org.lwjgl.util.opus.OpusFile;
import game.log.Log;
import game.rng.Random;
@ -124,10 +129,6 @@ public enum SoundEvent {
SLIME_SMALL("slime_small1", "slime_small2", "slime_small3", "slime_small4", "slime_small5");
private static final Random RANDOM = new Random();
private static final byte[] WAV_HDR = "RIFF".getBytes();
private static final byte[] WAV_HDR_FMT = "fmt ".getBytes();
private static final byte[] WAV_HDR_DATA = "data".getBytes();
private static final byte[] WAV_FORMAT = "WAVE".getBytes();
private final String[] sounds;
private final short[][] buffers;
@ -138,130 +139,68 @@ public enum SoundEvent {
for(int z = 0; z < entry.sounds.length; z++) {
String sound = entry.sounds[z];
Log.SOUND.trace("Lade Sound %s", sound);
entry.buffers[z] = readWav("sounds/" + sound + ".wav", 48000, (short)1);
entry.buffers[z] = readOpus("sounds/" + sound + ".opus");
}
}
}
private static int read32(byte[] data, int off) {
int value = 0;
for(int h = 0; h < 4; h++) {
value |= (int)((data[h + off]) & 0xff) << (8*h);
}
return value;
}
private static short read16(byte[] data, int off) {
short value = 0;
for(int h = 0; h < 2; h++) {
value |= (short)((data[h + off]) & 0xff) << (8*h);
}
return value;
}
private static boolean memcmp(byte[] d1, int off, byte[] d2, int size) {
for(int z = 0; z < size; z++) {
if(d1[z + off] != d2[z])
return true;
}
return false;
}
private static int readWavHeader(byte[] data, int samplerate, short channels, short bytes) {
if(memcmp(data, 0, WAV_HDR, 4)) {
Log.IO.debug("base header");
return 0;
}
int len = read32(data, 4);
if(memcmp(data, 8, WAV_FORMAT, 4)) {
Log.IO.debug("wave header");
return 0;
}
if(memcmp(data, 12, WAV_HDR_FMT, 4)) {
Log.IO.debug("fmt header");
return 0;
}
if(read32(data, 16) != 16) {
Log.IO.debug("header size");
return 0;
}
if(read16(data, 20) != 1) {
Log.IO.debug("pcm");
return 0;
}
if(read16(data, 22) != channels) {
Log.IO.debug("channels");
return 0;
}
if(read32(data, 24) != samplerate) {
Log.IO.debug("sample rate");
return 0;
}
if(read32(data, 28) != (samplerate * ((int)channels) * ((int)bytes))) {
Log.IO.debug("bitrate");
return 0;
}
if(read16(data, 32) != (channels * bytes)) {
Log.IO.debug("sample align");
return 0;
}
if(read16(data, 34) != (8 * bytes)) {
Log.IO.debug("sample size");
return 0;
}
return len;
}
private static short[] readWav(String filename, int samplerate, short channels) {
private static short[] readOpus(String filename) {
InputStream in = null;
byte[] data;
try {
InputStream fd = new BufferedInputStream(FileUtils.getResource(filename));
byte[] hdr = new byte[36];
if(fd.read(hdr, 0, 36) != 36) {
Log.IO.error("Fehler beim Lesen von WAV-Datei '%s': E/A-Fehler", filename);
fd.close();
return null;
}
if(readWavHeader(hdr, samplerate, channels, (short)2) == 0) {
Log.IO.error("Fehler beim Lesen von WAV-Datei '%s': Falsches oder fehlerhaftes Format", filename);
fd.close();
return null;
}
int len = 0;
do {
if(len != 0 && fd.skip(len) != len) {
Log.IO.error("Fehler beim Lesen von WAV-Datei '%s': E/A-Fehler", filename);
fd.close();
return null;
}
if(fd.read(hdr, 0, 8) != 8) {
Log.IO.error("Fehler beim Lesen von WAV-Datei '%s': E/A-Fehler", filename);
fd.close();
return null;
}
len = read32(hdr, 4);
}
while(memcmp(hdr, 0, WAV_HDR_DATA, 4));
int samples = len / ((int)channels * 2);
byte[] buf = new byte[samples * channels * 2];
if(fd.read(buf, 0, samples * channels * 2) != samples * channels * 2) {
Log.IO.error("Fehler beim Lesen von WAV-Datei '%s': E/A-Fehler", filename);
fd.close();
return null;
}
fd.close();
short[] sbuf = new short[samples * channels];
for(int z = 0; z < samples * channels; z++) {
sbuf[z] = read16(buf, z << 1);
}
return sbuf;
in = new BufferedInputStream(FileUtils.getResource(filename));
data = FileUtils.readBytes(in);
}
catch(FileNotFoundException e) {
Log.IO.error("Fehler beim Öffnen von WAV-Datei '%s': Datei nicht gefunden", filename);
Log.IO.error("Fehler beim Lesen von OPUS-Datei '%s': Datei nicht gefunden", filename);
return null;
}
catch(IOException e) {
Log.IO.error("Fehler beim Öffnen von WAV-Datei '%s': %s", filename, e.getMessage());
Log.IO.error("Fehler beim Lesen von OPUS-Datei '%s': %s", filename, e.getMessage());
return null;
}
return null;
finally {
try {
if(in != null)
in.close();
}
catch(IOException e) {
}
}
ByteBuffer buf = BufferUtils.createByteBuffer(data.length);
buf.put(data);
buf.flip();
long fd = OpusFile.op_open_memory(buf, null);
if(fd == 0L) {
Log.IO.error("Fehler beim Lesen von OPUS-Datei '%s': Falsches oder fehlerhaftes Format", filename);
return null;
}
if(OpusFile.op_channel_count(fd, -1) != 1) {
Log.IO.error("Fehler beim Lesen von OPUS-Datei '%s': Falsches Anzahl von Kanälen (!= 1)", filename);
OpusFile.op_free(fd);
return null;
}
long samples = OpusFile.op_pcm_total(fd, -1);
if(samples < 0L) {
Log.IO.error("Fehler beim Lesen von OPUS-Datei '%s': E/A-Fehler", filename);
OpusFile.op_free(fd);
return null;
}
ShortBuffer pcm = BufferUtils.createShortBuffer((int)samples);
int state;
while((state = OpusFile.op_read(fd, pcm, null)) > 0L) {
pcm.position(pcm.position() + state);
}
if(state < 0L) {
Log.IO.error("Fehler beim Lesen von OPUS-Datei '%s': E/A-Fehler", filename);
OpusFile.op_free(fd);
return null;
}
OpusFile.op_free(fd);
short[] decoded = new short[(int)samples];
pcm.rewind();
pcm.get(decoded);
return decoded;
}
private SoundEvent(String ... sounds) {