1
0
Fork 0

add bank loader

This commit is contained in:
Sen 2025-09-03 11:18:13 +02:00
parent 324332c242
commit ceda16246c
Signed by: sen
GPG key ID: 3AC50A6F47D1B722
35 changed files with 1118 additions and 35 deletions

View file

@ -2604,8 +2604,10 @@ public class Client implements IThreadListener {
}
private void startSound(boolean load) {
if(load)
if(load) {
SoundManager.loadSounds();
MidiBank.loadBanks();
}
this.audio = new AudioInterface(this.soundFrameSize, this.soundBufferSize, !this.soundEnabled);
boolean started = this.audio.start();
Log.flushLog();

View file

@ -0,0 +1,934 @@
package client.audio;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.Files;
import java.util.Arrays;
import client.util.FileUtils;
import common.log.Log;
public class BankLoader {
/*
enum bank_op {
b_op2,
b_op4,
b_op22,
b_op0
};
typedef struct {
uint8_t tremolo;
uint8_t vibrato;
uint8_t sustaining;
uint8_t ksr;
uint8_t mult;
uint8_t ksl;
uint8_t level;
uint8_t attack;
uint8_t decay;
uint8_t sustain;
uint8_t release;
uint8_t waveform;
} bank_operator;
typedef struct {
bank_operator ops[2];
int16_t detune;
int16_t offset;
uint8_t feedback;
uint8_t am;
} bank_pair;
typedef struct {
bank_pair channels[2];
uint8_t op;
uint8_t fixed;
uint8_t percnum;
char name[32];
} bank_instr;
*/
//#define STR_BNK_WRITERR "Fehler beim Schreiben nach Bank-Datei '%s': "
//#define STR_BNK_PARSERR "Fehler beim Verarbeiten von Bank-Datei '%s': "
//#define STR_BNK_EIO STR_BNK_READERR "E/A-Fehler"
//#define STR_BNK_EEOF STR_BNK_READERR "Ende der Datei erreicht"
//#define STR_BNK_EWIO STR_BNK_WRITERR "E/A-Fehler"
//#define STR_BNK_EEOD STR_BNK_PARSERR "Ende der Daten erreicht"
private static byte[] bnk_read_mhbank(byte[] raw, String filename, int minsize, int maxsize, byte[] hdr) {
int size = raw.length;
if(size < (hdr == null ? 0 : hdr.length) + minsize) {
Log.SOUND.error("Fehler beim Lesen von Bank-Datei '%s': Datei zu klein", filename);
return null;
}
if(hdr != null) {
if(!Arrays.equals(raw, 0, hdr.length, hdr, 0, hdr.length)) {
Log.SOUND.error("Fehler beim Lesen von Bank-Datei '%s': Fehlerhafter Dateiheader oder falscher Dateityp", filename);
return null;
}
size -= hdr.length;
}
size = maxsize > 0 && size > maxsize ? maxsize : size;
if(size != raw.length) {
byte[] data = new byte[size];
System.arraycopy(raw, hdr == null ? 0 : hdr.length, data, 0, data.length);
return data;
}
return raw;
}
private static byte[] bnk_read_mbank(byte[] raw, String filename, int minsize, int maxsize) {
return bnk_read_mhbank(raw, filename, minsize, maxsize, null);
}
private static byte[] bnk_read_hbank(byte[] raw, String filename, int size, byte[] hdr) {
return bnk_read_mhbank(raw, filename, size, size, hdr);
}
private static byte[] bnk_read_sbank(byte[] raw, String filename, int size) {
return bnk_read_mhbank(raw, filename, size, size, null);
}
private static char dmx_read_uint16(byte[] data, int offset) {
char value = 0;
for(int h = 0; h < 2; h++) {
value |= ((char)(data[offset + 1 - h] & 255));
value <<= h < 1 ? 8 : 0;
}
return value;
}
private static char dmx_read_uint16be(byte[] data, int offset) {
char value = 0;
for(int h = 0; h < 2; h++) {
value |= ((char)(data[offset + h] & 255));
value <<= h < 1 ? 8 : 0;
}
return value;
}
private static Instrument dmx_read_instr(byte[] data, int offset, boolean drum) {
boolean fixed = ((data[offset + 0] & 0x01) != 0) || drum;
boolean op2x2 = ((data[offset + 0] & 0x04) != 0);
int ch2detune = (int)(data[offset + 2] & 255) - 128;
int percnum = data[offset + 3] & 0x7f;
offset += 4;
Operator[] ops = new Operator[op2x2 ? 4 : 2];
int[] fb = new int[2];
int algo = op2x2 ? 0x08 : 0x00;
for(int ch = 0; ch < (op2x2 ? 2 : 1); ch++) {
int transpose = (int)dmx_read_uint16(data, offset + 14) + 12;
for(int op = 0; op < 2; op++) {
boolean tremolo = (data[offset + op*7+0] & 0x80) != 0;
boolean vibrato = (data[offset + op*7+0] & 0x40) != 0;
boolean sustaining = (data[offset + op*7+0] & 0x20) != 0;
boolean ksr = (data[offset + op*7+0] & 0x10) != 0;
int mult = data[offset + op*7+0] & 0x0f;
int attack = ((data[offset + op*7+1] & 255) >> 4) & 0x0f;
int decay = data[offset + op*7+1] & 0x0f;
int sustain = ((data[offset + op*7+2] & 255) >> 4) & 0x0f;
int release = data[offset + op*7+2] & 0x0f;
int waveform = data[offset + op*7+3] & 0x07;
int ksl = ((data[offset + op*7+4] & 255) >> 6) & 0x03;
int level = data[offset + op*7+5] & 0x3f;
int detune = ch == 1 ? ch2detune : 0;
ops[ch * 2 + op] = new Operator(mult, level, waveform, attack, decay, sustain, release, tremolo, vibrato, sustaining, ksr, ksl, transpose, detune);
}
fb[ch] = (data[offset + 6] >> 1) & 0x07;
algo |= (data[offset + 6] & 0x01) != 0 ? 1 << ch : 0;
offset += 16;
}
Instrument ins = new Instrument(fb[0], fb[1], algo, ops);
if(fixed)
ins.setFixed(percnum);
return ins;
}
private static Instrument[] dmx_read_bank(byte[] raw, String filename) {
byte[] data = bnk_read_hbank(raw, filename, 175 * 68, "#OPL_II#".getBytes());
if(data == null)
return null;
Instrument[] instr = new Instrument[256];
for(int i = 0; i < instr.length; i++) {
instr[i] = new Instrument();
}
int offset = 0;
for(int i = 0; i < 175; i++) {
instr[(i < 128) ? i : (i + 35)] = dmx_read_instr(data, offset, i >= 128);
offset += 36;
}
for(int i = 0; i < 175; i++) {
Instrument ins = instr[(i < 128) ? i : (i + 35)];
int len = 0;
while(len < 32 && data[offset + len] != 0) {
++len;
}
ins.setName(new String(data, offset, len));
offset += 32;
}
return instr;
}
/*
private static void tmb_read_instr(bank_instr *instr, uint8_t *data, uint8_t drum) {
instr->name[0] = 0;
instr->fixed = drum;
instr->op = b_op2;
for(int op = 0; op < 2; op++) {
instr->channels[0].ops[op].tremolo = (data[op+0] & 0x80) > 0;
instr->channels[0].ops[op].vibrato = (data[op+0] & 0x40) > 0;
instr->channels[0].ops[op].sustaining = (data[op+0] & 0x20) > 0;
instr->channels[0].ops[op].ksr = (data[op+0] & 0x10) > 0;
instr->channels[0].ops[op].mult = data[op+0] & 0x0f;
instr->channels[0].ops[op].attack = (data[op+4] >> 4) & 0x0f;
instr->channels[0].ops[op].decay = data[op+4] & 0x0f;
instr->channels[0].ops[op].sustain = (data[op+6] >> 4) & 0x0f;
instr->channels[0].ops[op].release = data[op+6] & 0x0f;
instr->channels[0].ops[op].waveform = data[op+8] & 0x07;
instr->channels[0].ops[op].ksl = (data[op+2] >> 6) & 0x03;
instr->channels[0].ops[op].level = data[op+2] & 0x3f;
}
instr->channels[0].feedback = (data[10] >> 1) & 0x07;
instr->channels[0].am = data[10] & 0x01;
instr->percnum = drum ? (data[11] & 0x7f) : 0;
instr->channels[0].offset = drum ? 0 : ((int8_t)data[11]);
instr->channels[0].detune = 0;
}
bank_instr *tmb_read_bank(const char *filename) {
uint8_t *data;
bank_instr *instr;
uint32_t size = bnk_read_sbank(&data, &instr, filename, 256*13);
if(size == 0) {
return NULL;
}
uint8_t *odata = data;
for(int i = 0; i < 256; i++) {
tmb_read_instr(&instr[i], data, i >= 128);
data += 13;
}
free(odata);
return instr;
}
void ibk_read_instr(bank_instr *instr, uint8_t *data, uint8_t drum) {
instr->fixed = drum;
instr->op = b_op2;
for(int op = 0; op < 2; op++) {
instr->channels[0].ops[op].tremolo = (data[op+0] & 0x80) > 0;
instr->channels[0].ops[op].vibrato = (data[op+0] & 0x40) > 0;
instr->channels[0].ops[op].sustaining = (data[op+0] & 0x20) > 0;
instr->channels[0].ops[op].ksr = (data[op+0] & 0x10) > 0;
instr->channels[0].ops[op].mult = data[op+0] & 0x0f;
instr->channels[0].ops[op].attack = (data[op+4] >> 4) & 0x0f;
instr->channels[0].ops[op].decay = data[op+4] & 0x0f;
instr->channels[0].ops[op].sustain = (data[op+6] >> 4) & 0x0f;
instr->channels[0].ops[op].release = data[op+6] & 0x0f;
instr->channels[0].ops[op].waveform = data[op+8] & 0x07;
instr->channels[0].ops[op].ksl = (data[op+2] >> 6) & 0x03;
instr->channels[0].ops[op].level = data[op+2] & 0x3f;
}
instr->channels[0].feedback = (data[10] >> 1) & 0x07;
instr->channels[0].am = data[10] & 0x01;
instr->percnum = drum ? (data[13] & 0x7f) : 0;
instr->channels[0].offset = drum ? 0 : ((int8_t)data[13]);
instr->channels[0].detune = 0;
}
bank_instr *ibk_read_bank(const char *filename, uint8_t drum) {
uint8_t *data;
bank_instr *instr;
uint32_t size = bnk_read_hbank(&data, &instr, filename, 128*25, "IBK\x1a", 4);
if(size == 0) {
return NULL;
}
uint8_t *odata = data;
for(int i = 0; i < 128; i++) {
instr[i + (drum ? 0 : 128)].op = b_op0;
instr[i + (drum ? 0 : 128)].name[0] = 0;
}
for(int i = 0; i < 128; i++) {
ibk_read_instr(&instr[i + (drum ? 128 : 0)], data, drum);
data += 16;
}
for(int i = 0; i < 128; i++) {
bank_instr *ins = &instr[i + (drum ? 128 : 0)];
memcpy(ins->name, data, 8);
ins->name[8] = 0;
data += 9;
}
free(odata);
return instr;
}
void sb_read_instr(bank_instr *instr, uint8_t *data, uint8_t drum) {
for(int h = 0; h < 28; h++) {
instr->name[h] = (data[h] == 0x1a) ? ' ' : data[h];
}
instr->name[28] = 0;
instr->percnum = data[35] & 0x7f;
instr->fixed = drum;
instr->op = b_op2;
data += 36;
for(int op = 0; op < 2; op++) {
instr->channels[0].ops[op].tremolo = (data[op+0] & 0x80) > 0;
instr->channels[0].ops[op].vibrato = (data[op+0] & 0x40) > 0;
instr->channels[0].ops[op].sustaining = (data[op+0] & 0x20) > 0;
instr->channels[0].ops[op].ksr = (data[op+0] & 0x10) > 0;
instr->channels[0].ops[op].mult = data[op+0] & 0x0f;
instr->channels[0].ops[op].attack = (data[op+4] >> 4) & 0x0f;
instr->channels[0].ops[op].decay = data[op+4] & 0x0f;
instr->channels[0].ops[op].sustain = (data[op+6] >> 4) & 0x0f;
instr->channels[0].ops[op].release = data[op+6] & 0x0f;
instr->channels[0].ops[op].waveform = data[op+8] & 0x07;
instr->channels[0].ops[op].ksl = (data[op+2] >> 6) & 0x03;
instr->channels[0].ops[op].level = data[op+2] & 0x3f;
}
instr->channels[0].feedback = (data[10] >> 1) & 0x07;
instr->channels[0].am = data[10] & 0x01;
instr->channels[0].offset = 0;
instr->channels[0].detune = 0;
}
bank_instr *sb_read_bank(const char *filename, uint8_t drum) {
uint8_t *data;
bank_instr *instr;
uint32_t size = bnk_read_sbank(&data, &instr, filename, 128*52);
if(size == 0) {
return NULL;
}
uint8_t *odata = data;
for(int i = 0; i < 128; i++) {
instr[i + (drum ? 0 : 128)].op = b_op0;
instr[i + (drum ? 0 : 128)].name[0] = 0;
}
for(int i = 0; i < 128; i++) {
sb_read_instr(&instr[i + (drum ? 128 : 0)], data, drum);
data += 52;
}
free(odata);
return instr;
}
void sb3_read_instr(bank_instr *instr, uint8_t *data, uint8_t drum) {
for(int h = 0; h < 28; h++) {
instr->name[h] = (data[h] == 0x1a) ? ' ' : data[h];
}
instr->name[28] = 0;
instr->percnum = data[35] & 0x7f;
instr->fixed = drum;
instr->op = (data[0] == '4') ? b_op4 : b_op2;
data += 36;
for(int ch = 0; ch < 2; ch++) {
for(int op = 0; op < 2; op++) {
instr->channels[ch].ops[op].tremolo = (data[op+0] & 0x80) > 0;
instr->channels[ch].ops[op].vibrato = (data[op+0] & 0x40) > 0;
instr->channels[ch].ops[op].sustaining = (data[op+0] & 0x20) > 0;
instr->channels[ch].ops[op].ksr = (data[op+0] & 0x10) > 0;
instr->channels[ch].ops[op].mult = data[op+0] & 0x0f;
instr->channels[ch].ops[op].attack = (data[op+4] >> 4) & 0x0f;
instr->channels[ch].ops[op].decay = data[op+4] & 0x0f;
instr->channels[ch].ops[op].sustain = (data[op+6] >> 4) & 0x0f;
instr->channels[ch].ops[op].release = data[op+6] & 0x0f;
instr->channels[ch].ops[op].waveform = data[op+8] & 0x07;
instr->channels[ch].ops[op].ksl = (data[op+2] >> 6) & 0x03;
instr->channels[ch].ops[op].level = data[op+2] & 0x3f;
}
instr->channels[ch].feedback = (data[10] >> 1) & 0x07;
instr->channels[ch].am = data[10] & 0x01;
instr->channels[ch].offset = 0;
instr->channels[ch].detune = 0;
data += 11;
}
}
bank_instr *sb3_read_bank(const char *filename, uint8_t drum) {
uint8_t *data;
bank_instr *instr;
uint32_t size = bnk_read_sbank(&data, &instr, filename, 128*60);
if(size == 0) {
return NULL;
}
uint8_t *odata = data;
for(int i = 0; i < 128; i++) {
instr[i + (drum ? 0 : 128)].op = b_op0;
instr[i + (drum ? 0 : 128)].name[0] = 0;
}
for(int i = 0; i < 128; i++) {
sb3_read_instr(&instr[i + (drum ? 128 : 0)], data, drum);
data += 60;
}
free(odata);
return instr;
}
void op3_read_instr(bank_instr *instr, uint8_t *data, uint8_t drum) {
instr->percnum = data[1] & 0x7f;
instr->fixed = drum;
instr->op = ((data[0] & 0x01) > 0) ? b_op4 : b_op2;
data += 2;
for(int ch = 0; ch < 2; ch++) {
for(int op = 0; op < 2; op++) {
instr->channels[ch].ops[op].tremolo = (data[op*6+0] & 0x80) > 0;
instr->channels[ch].ops[op].vibrato = (data[op*6+0] & 0x40) > 0;
instr->channels[ch].ops[op].sustaining = (data[op*6+0] & 0x20) > 0;
instr->channels[ch].ops[op].ksr = (data[op*6+0] & 0x10) > 0;
instr->channels[ch].ops[op].mult = data[op*6+0] & 0x0f;
instr->channels[ch].ops[op].attack = (data[op*6+2] >> 4) & 0x0f;
instr->channels[ch].ops[op].decay = data[op*6+2] & 0x0f;
instr->channels[ch].ops[op].sustain = (data[op*6+3] >> 4) & 0x0f;
instr->channels[ch].ops[op].release = data[op*6+3] & 0x0f;
instr->channels[ch].ops[op].waveform = data[op*6+4] & 0x07;
instr->channels[ch].ops[op].ksl = (data[op*6+1] >> 6) & 0x03;
instr->channels[ch].ops[op].level = data[op*6+1] & 0x3f;
}
instr->channels[ch].feedback = (data[5] >> 1) & 0x07;
instr->channels[ch].am = data[5] & 0x01;
instr->channels[ch].offset = 0;
instr->channels[ch].detune = 0;
data += 11;
}
}
bank_instr *op3_read_bank(const char *filename) {
uint8_t *data;
bank_instr *instr;
uint32_t size = bnk_read_mhbank(&data, &instr, filename, 16, 256*24+16, "Junglevision Patch File\x1a", 24);
if(size == 0) {
return NULL;
}
uint8_t *odata = data;
for(int i = 0; i < 256; i++) {
instr[i].op = b_op0;
instr[i].name[0] = 0;
}
data += 8;
uint16_t nmelo = dmx_read_uint16(&data[0]);
uint16_t ndrum = dmx_read_uint16(&data[2]);
uint16_t omelo = dmx_read_uint16(&data[4]);
uint16_t odrum = dmx_read_uint16(&data[6]);
data += 8;
if((((nmelo+ndrum)*24+16) > size) || ((omelo+nmelo) > 128) || ((odrum+ndrum) > 128)) {
fprintf(stderr, STR_BNK_EEOD"\n", filename);
free(odata);
free(instr);
return NULL;
}
for(int i = 0; i < nmelo; i++) {
op3_read_instr(&instr[i + omelo], data, 0);
data += 24;
}
for(int i = 0; i < ndrum; i++) {
op3_read_instr(&instr[i + odrum + 128], data, 1);
data += 24;
}
free(odata);
return instr;
}
void ad_read_instr(bank_instr *instr, uint8_t *data, uint8_t drum, uint16_t isize) {
if(isize < 12) {
return;
}
instr->percnum = data[0] & 0x7f;
instr->fixed = drum;
instr->op = (isize >= 23) ? b_op4 : b_op2;
data += 1;
instr->channels[0].feedback = instr->channels[1].feedback = (data[5] >> 1) & 0x07;
instr->channels[0].am = data[5] & 0x01;
instr->channels[1].am = (data[5] & 0x80) > 0;
for(int ch = 0; ch < ((isize >= 23) ? 2 : 1); ch++) {
for(int op = 0; op < 2; op++) {
instr->channels[ch].ops[op].tremolo = (data[op*6+0] & 0x80) > 0;
instr->channels[ch].ops[op].vibrato = (data[op*6+0] & 0x40) > 0;
instr->channels[ch].ops[op].sustaining = (data[op*6+0] & 0x20) > 0;
instr->channels[ch].ops[op].ksr = (data[op*6+0] & 0x10) > 0;
instr->channels[ch].ops[op].mult = data[op*6+0] & 0x0f;
instr->channels[ch].ops[op].attack = (data[op*6+2] >> 4) & 0x0f;
instr->channels[ch].ops[op].decay = data[op*6+2] & 0x0f;
instr->channels[ch].ops[op].sustain = (data[op*6+3] >> 4) & 0x0f;
instr->channels[ch].ops[op].release = data[op*6+3] & 0x0f;
instr->channels[ch].ops[op].waveform = data[op*6+4] & 0x07;
instr->channels[ch].ops[op].ksl = (data[op*6+1] >> 6) & 0x03;
instr->channels[ch].ops[op].level = data[op*6+1] & 0x3f;
}
instr->channels[ch].offset = 0;
instr->channels[ch].detune = 0;
data += 11;
}
}
bank_instr *ad_read_bank(const char *filename) {
uint8_t *data;
bank_instr *instr;
uint32_t size = bnk_read_mbank(&data, &instr, filename, 2, 256*20+2);
if(size == 0) {
return NULL;
}
uint8_t *odata = data;
for(int i = 0; i < 256; i++) {
instr[i].op = b_op0;
instr[i].name[0] = 0;
}
for(int i = 0;; i++, data += 6) {
if((i*6) >= size) {
fprintf(stderr, STR_BNK_EEOD"\n", filename);
free(odata);
free(instr);
return NULL;
}
uint8_t prog = data[0];
if(prog == 0xff) {
break;
}
if(prog >= 128) {
continue;
}
uint8_t bank = data[1];
if((bank != 0) && (bank != 127)) {
continue;
}
uint16_t offs = dmx_read_uint16(data+2);
uint16_t isize;
if(((offs+2) > size) || ((offs+(isize = dmx_read_uint16(odata+offs))) > size) || (isize < 2)) {
fprintf(stderr, STR_BNK_EEOD"\n", filename);
free(odata);
free(instr);
return NULL;
}
ad_read_instr(&instr[prog + ((bank == 127) ? 128 : 0)], odata+(offs+2), bank == 127, isize-2);
}
free(odata);
return instr;
}
void bk_read_instr(bank_instr *instr, uint8_t *data, uint8_t drum) {
instr->fixed = drum;
instr->op = b_op2;
for(int op = 0; op < 2; op++) {
instr->channels[0].ops[op].tremolo = data[op*13+9] & 0x01;
instr->channels[0].ops[op].vibrato = data[op*13+10] & 0x01;
instr->channels[0].ops[op].sustaining = data[op*13+5] & 0x01;
instr->channels[0].ops[op].ksr = data[op*13+11] & 0x01;
instr->channels[0].ops[op].mult = data[op*13+1] & 0x0f;
instr->channels[0].ops[op].attack = data[op*13+3] & 0x0f;
instr->channels[0].ops[op].decay = data[op*13+6] & 0x0f;
instr->channels[0].ops[op].sustain = data[op*13+4] & 0x0f;
instr->channels[0].ops[op].release = data[op*13+7] & 0x0f;
instr->channels[0].ops[op].waveform = data[26+op] & 0x07;
instr->channels[0].ops[op].ksl = data[op*13+0] & 0x03;
instr->channels[0].ops[op].level = data[op*13+8] & 0x3f;
}
instr->channels[0].feedback = data[2] & 0x07;
instr->channels[0].am = (data[25] & 0x01) ^ 1;
instr->channels[0].offset = 0;
instr->channels[0].detune = 0;
}
bank_instr *bk_read_bank(const char *filename, uint8_t drum) {
uint8_t *data;
bank_instr *instr;
uint32_t size = bnk_read_mbank(&data, &instr, filename, 28, 256*42+28);
if(size == 0) {
return NULL;
}
uint8_t *odata = data;
if(memcmp(data+2, "ADLIB-", 6) != 0) {
fprintf(stderr, STR_BNK_EMFHDR"\n", filename);
free(odata);
free(instr);
return NULL;
}
data += 8;
for(int i = 0; i < 256; i++) {
instr[i].op = b_op0;
instr[i].name[0] = 0;
}
// uint16_t nnorm = data[0];
uint32_t ninst = dmx_read_uint16(&data[2]);
data += 20;
if((ninst*42+28) > size) {
fprintf(stderr, STR_BNK_EEOD"\n", filename);
free(odata);
free(instr);
return NULL;
}
data += ninst*12;
int pos = 0;
for(int i = 0; i < ninst; i++, data += 30) {
if(data[0] != 0) {
continue;
}
bk_read_instr(&instr[pos + (drum ? 128 : 0)], data+2, drum);
uint8_t *ndata = odata+(i*12+28);
instr[pos + (drum ? 128 : 0)].percnum = ndata[2] & 0x7f;
memcpy(instr[pos + (drum ? 128 : 0)].name, ndata+3, 8);
instr[pos + (drum ? 128 : 0)].name[8] = 0;
if(++pos == 128) {
break;
}
}
free(odata);
return instr;
}
void tim_read_instr(bank_instr *instr, uint8_t *data) {
instr->percnum = 0;
instr->fixed = 0;
instr->op = b_op2;
for(int op = 0; op < 2; op++) {
instr->channels[0].ops[op].tremolo = dmx_read_uint16(&data[op*26+18]) & 0x01;
instr->channels[0].ops[op].vibrato = dmx_read_uint16(&data[op*26+20]) & 0x01;
instr->channels[0].ops[op].sustaining = dmx_read_uint16(&data[op*26+10]) & 0x01;
instr->channels[0].ops[op].ksr = dmx_read_uint16(&data[op*26+22]) & 0x01;
instr->channels[0].ops[op].mult = dmx_read_uint16(&data[op*26+2]) & 0x0f;
instr->channels[0].ops[op].attack = dmx_read_uint16(&data[op*26+6]) & 0x0f;
instr->channels[0].ops[op].decay = dmx_read_uint16(&data[op*26+12]) & 0x0f;
instr->channels[0].ops[op].sustain = dmx_read_uint16(&data[op*26+8]) & 0x0f;
instr->channels[0].ops[op].release = dmx_read_uint16(&data[op*26+14]) & 0x0f;
instr->channels[0].ops[op].waveform = dmx_read_uint16(&data[52+op*2]) & 0x07;
instr->channels[0].ops[op].ksl = dmx_read_uint16(&data[op*26+0]) & 0x03;
instr->channels[0].ops[op].level = dmx_read_uint16(&data[op*26+16]) & 0x3f;
}
instr->channels[0].feedback = dmx_read_uint16(&data[4]) & 0x07;
instr->channels[0].am = (dmx_read_uint16(&data[50]) & 0x01) ^ 1;
instr->channels[0].offset = 0;
instr->channels[0].detune = 0;
}
bank_instr *tim_read_bank(const char *filename, uint8_t drum) {
uint8_t *data;
bank_instr *instr;
uint32_t size = bnk_read_mbank(&data, &instr, filename, 6, 256*65+6);
if(size == 0) {
return NULL;
}
uint8_t *odata = data;
for(int i = 0; i < 256; i++) {
instr[i].op = b_op0;
instr[i].name[0] = 0;
}
uint32_t ninst = dmx_read_uint16(&data[2]);
data += 6;
if((ninst*65+6) > size) {
fprintf(stderr, STR_BNK_EEOD"\n", filename);
free(odata);
free(instr);
return NULL;
}
data += ninst*9;
for(int i = 0; (i < ninst) && (i < 128); i++, data += 56) {
tim_read_instr(&instr[i + (drum ? 128 : 0)], data);
uint8_t *ndata = odata+(i*9+6);
memcpy(instr[i + (drum ? 128 : 0)].name, ndata, 8);
instr[i + (drum ? 128 : 0)].name[8] = 0;
}
free(odata);
return instr;
}
void wopl_read_instr(bank_instr *instr, uint8_t *data, uint8_t drum) {
memcpy(instr->name, data, 32);
instr->name[31] = 0;
data += 32;
instr->percnum = data[6] & 0x7f;
instr->fixed = drum;
instr->op = (data[7] & 0x01) ? (((data[7] & 0x02) > 0) ? b_op22 : b_op4) : b_op2;
instr->channels[0].offset = (int16_t)dmx_read_uint16be(&data[0]);
instr->channels[0].detune = 0;
if(instr->op != b_op2) {
instr->channels[1].offset = (int16_t)dmx_read_uint16be(&data[2]);
instr->channels[0].detune = (int8_t)data[5];
}
instr->channels[0].am = data[8] & 0x01;
instr->channels[0].feedback = (data[8] >> 1) & 0x07;
if(instr->op != b_op2) {
instr->channels[1].am = data[9] & 0x01;
instr->channels[1].feedback = (data[9] >> 1) & 0x07;
}
data += 10;
for(int ch = 0; ch < ((instr->op != b_op2) ? 2 : 1); ch++) {
for(int op = 0; op < 2; op++) {
instr->channels[ch].ops[1-op].tremolo = (data[op*5+0] & 0x80) > 0;
instr->channels[ch].ops[1-op].vibrato = (data[op*5+0] & 0x40) > 0;
instr->channels[ch].ops[1-op].sustaining = (data[op*5+0] & 0x20) > 0;
instr->channels[ch].ops[1-op].ksr = (data[op*5+0] & 0x10) > 0;
instr->channels[ch].ops[1-op].mult = data[op*5+0] & 0x0f;
instr->channels[ch].ops[1-op].attack = (data[op*5+2] >> 4) & 0x0f;
instr->channels[ch].ops[1-op].decay = data[op*5+2] & 0x0f;
instr->channels[ch].ops[1-op].sustain = (data[op*5+3] >> 4) & 0x0f;
instr->channels[ch].ops[1-op].release = data[op*5+3] & 0x0f;
instr->channels[ch].ops[1-op].waveform = data[op*5+4] & 0x07;
instr->channels[ch].ops[1-op].ksl = (data[op*5+1] >> 6) & 0x03;
instr->channels[ch].ops[1-op].level = data[op*5+1] & 0x3f;
}
data += 10;
}
}
bank_instr *wopl_read_bank(const char *filename) {
uint8_t *data;
bank_instr *instr;
uint32_t size = bnk_read_mhbank(&data, &instr, filename, 256*62+9, 512*66+77, "WOPL3-BANK", 10);
if(size == 0) {
return NULL;
}
uint8_t *odata = data;
int stride = (data[7] != 0) ? 66 : 62;
int off = (data[7] != 0) ? 77 : 9 + ((data[4] == 2) ? 102 : 0);
int off2 = (data[4] == 2) ? (128*stride) : 0;
if((256*stride+off+off2) > size) {
fprintf(stderr, STR_BNK_EEOD"\n", filename);
free(odata);
free(instr);
return NULL;
}
data += off;
for(int i = 0; i < 128; i++) {
wopl_read_instr(&instr[i], data, 0);
data += stride;
}
data += off2;
for(int i = 0; i < 128; i++) {
wopl_read_instr(&instr[i + 128], data, 1);
data += stride;
}
free(odata);
return instr;
}
// SKB!
// OO-NNNNN NAME[N] FPPPPPPP AFFFAFFF
// DDDDDDDD OOOOOOOO TVSKMMMM KKLLLLLL AAAADDDD SSSSRRRR TVSKMMMM KKLLLLLL AAAADDDD SSSSRRRR -WWW-WWW
uint32_t skb_read_instr(bank_instr *instr, uint8_t *data, uint32_t pos, uint32_t size) {
if((pos + 1) > size) {
return 0;
}
data += pos;
instr->op = (data[0] >> 6) & 0x03;
uint8_t nlen = data[0] & 0x1f;
if((pos + 1 + nlen) > size) {
return 0;
}
memcpy(instr->name, data+1, nlen);
instr->name[nlen] = 0;
pos += 1 + nlen;
if(instr->op == b_op0) {
return pos;
}
int numch = (instr->op == b_op2) ? 1 : 2;
if((pos + 1 + (12 * numch)) > size) {
return 0;
}
data += 1 + nlen;
instr->fixed = (data[0] & 0x80) > 0;
instr->percnum = data[0] & 0x7f;
instr->channels[0].am = (data[1] & 0x08) > 0;
instr->channels[0].feedback = data[1] & 0x07;
if(numch == 2) {
instr->channels[1].am = (data[1] & 0x80) > 0;
instr->channels[1].feedback = (data[1] >> 4) & 0x07;
}
data += 2;
for(int ch = 0; ch < numch; ch++) {
instr->channels[ch].detune = ((int16_t)data[0]) - 128;
instr->channels[ch].offset = ((int16_t)data[1]) - 128;
data += 2;
for(int op = 0; op < 2; op++) {
instr->channels[ch].ops[op].tremolo = (data[0] & 0x80) > 0;
instr->channels[ch].ops[op].vibrato = (data[0] & 0x40) > 0;
instr->channels[ch].ops[op].sustaining = (data[0] & 0x20) > 0;
instr->channels[ch].ops[op].ksr = (data[0] & 0x10) > 0;
instr->channels[ch].ops[op].mult = data[0] & 0x0f;
instr->channels[ch].ops[op].ksl = (data[1] >> 6) & 0x03;
instr->channels[ch].ops[op].level = data[1] & 0x3f;
instr->channels[ch].ops[op].attack = (data[2] >> 4) & 0x0f;
instr->channels[ch].ops[op].decay = data[2] & 0x0f;
instr->channels[ch].ops[op].sustain = (data[3] >> 4) & 0x0f;
instr->channels[ch].ops[op].release = data[3] & 0x0f;
data += 4;
}
instr->channels[ch].ops[0].waveform = (data[0] >> 4) & 0x07;
instr->channels[ch].ops[1].waveform = data[0] & 0x07;
data += 1;
}
return pos + 2 + (11 * numch);
}
bank_instr *skb_read_bank(const char *filename) {
uint8_t *data;
bank_instr *instr;
uint32_t size = bnk_read_mhbank(&data, &instr, filename, 256, 256*56, "SKB!", 4);
if(size == 0) {
return NULL;
}
uint32_t pos = 0;
for(int i = 0; i < 256; i++) {
pos = skb_read_instr(&instr[i], data, pos, size);
if(pos == 0) {
fprintf(stderr, STR_BNK_EEOD"\n", filename);
free(data);
free(instr);
return NULL;
}
}
free(data);
return instr;
}
*/
private static Instrument[] bnk_read_bank(byte[] raw, String name, boolean drum) {
int dot = name.lastIndexOf('.');
if(dot < 0 || dot == name.length() - 1) {
Log.SOUND.error("Bank-Datei '%s' hat keine Erweiterung", name);
return null;
}
String ext = name.substring(dot + 1);
// if(strcmp(ext, "skb") == 0) {
// return skb_read_bank(filename);
// }
// else
if(ext.equalsIgnoreCase("dmx") || ext.equalsIgnoreCase("op2") || ext.equalsIgnoreCase("lmp")) {
return dmx_read_bank(raw, name);
}
// else if(strcmp(ext, "tmb") == 0) {
// return tmb_read_bank(filename);
// }
// else if(strcmp(ext, "ibk") == 0) {
// return ibk_read_bank(filename, drum);
// }
// else if(strcmp(ext, "sb") == 0) {
// return sb_read_bank(filename, drum);
// }
// else if(strcmp(ext, "o3") == 0) {
// return sb3_read_bank(filename, drum);
// }
// else if(strcmp(ext, "op3") == 0) {
// return op3_read_bank(filename);
// }
// else if((strcmp(ext, "ad") == 0) || (strcmp(ext, "opl") == 0)) {
// return ad_read_bank(filename);
// }
// else if(strcmp(ext, "bnk") == 0) {
// return bk_read_bank(filename, drum);
// }
// else if((strcmp(ext, "tim") == 0) || (strcmp(ext, "snd") == 0)) {
// return tim_read_bank(filename, drum);
// }
// else if(strcmp(ext, "wopl") == 0) {
// return wopl_read_bank(filename);
// }
Log.SOUND.error("Format von Bank-Datei '%s' unbekannt", name);
return null;
}
private static Instrument[] readBank(File file, boolean drum) {
byte[] raw;
try {
raw = Files.readAllBytes(file.toPath());
}
catch(FileNotFoundException e) {
Log.SOUND.error("Fehler beim Lesen von Bank-Datei '%s': Datei nicht gefunden", file);
return null;
}
catch(IOException e) {
Log.SOUND.error(e, "Fehler beim Lesen von Bank-Datei '%s'", file);
return null;
}
return bnk_read_bank(raw, file.getAbsolutePath(), drum);
}
private static Instrument[] readBank(String path, boolean drum) {
byte[] raw;
try {
raw = FileUtils.readBytes(path);
}
catch(FileNotFoundException e) {
Log.SOUND.error("Fehler beim Lesen von Bank-Datei '%s': Datei nicht gefunden", path);
return null;
}
catch(IOException e) {
Log.SOUND.error(e, "Fehler beim Lesen von Bank-Datei '%s'", path);
return null;
}
return bnk_read_bank(raw, path, drum);
}
public static Instrument[] readBank(String filename, String drumname, boolean usedrum) {
Instrument[] ins1 = readBank(filename, usedrum);
if(ins1 != null && drumname != null) {
Instrument[] ins2 = readBank(drumname, !usedrum);
if(ins2 == null)
return null;
System.arraycopy(ins2, 128, ins1, 128, 128);
}
return ins1;
}
/*
uint32_t skb_write_instr(bank_instr *instr, uint8_t *data, uint32_t pos) {
data += pos;
uint8_t nlen = strlen(instr->name);
data[0] = (instr->op << 6) | nlen;
memcpy(data+1, instr->name, nlen);
pos += 1 + nlen;
if(instr->op == b_op0) {
return pos;
}
int numch = (instr->op == b_op2) ? 1 : 2;
data += 1 + nlen;
data[0] = (instr->fixed << 7) | instr->percnum;
data[1] = ((numch == 2) ? ((instr->channels[1].am << 7) | (instr->channels[1].feedback << 4)) : 0) | (instr->channels[0].am << 3) | instr->channels[0].feedback;
data += 2;
for(int ch = 0; ch < numch; ch++) {
data[0] = (uint8_t)((int16_t)(instr->channels[ch].detune + 128));
data[1] = (uint8_t)((int16_t)(instr->channels[ch].offset + 128));
data += 2;
for(int op = 0; op < 2; op++) {
data[0] = (instr->channels[ch].ops[op].tremolo << 7) | (instr->channels[ch].ops[op].vibrato << 6) | (instr->channels[ch].ops[op].sustaining << 5) |
(instr->channels[ch].ops[op].ksr << 4) | instr->channels[ch].ops[op].mult;
data[1] = (instr->channels[ch].ops[op].ksl << 6) | instr->channels[ch].ops[op].level;
data[2] = (instr->channels[ch].ops[op].attack << 4) | instr->channels[ch].ops[op].decay;
data[3] = (instr->channels[ch].ops[op].sustain << 4) | instr->channels[ch].ops[op].release;
data += 4;
}
data[0] = (instr->channels[ch].ops[0].waveform << 4) | instr->channels[ch].ops[1].waveform;
data += 1;
}
return pos + 2 + (11 * numch);
}
bool skb_write_bank(bank_instr *instr, const char *filename) {
int err;
FILE *fd = fopen(filename, "wb");
if(fd == NULL) {
err = errno;
fprintf(stderr, STR_BNK_OPNERR"\n", filename, strerror(err), err);
return false;
}
if(fwrite("SKB!", 1, 4, fd) != 4) {
fprintf(stderr, STR_BNK_EWIO"\n", filename);
fclose(fd);
return false;
}
uint8_t *data = malloc(256*56);
uint32_t size = 0;
for(int i = 0; i < 256; i++) {
size = skb_write_instr(&instr[i], data, size);
}
if(fwrite(data, 1, size, fd) != size) {
fprintf(stderr, STR_BNK_EWIO"\n", filename);
fclose(fd);
free(data);
return false;
}
fclose(fd);
free(data);
return true;
}
*/
}

View file

@ -8,6 +8,7 @@ public class Instrument {
public boolean fixed;
public int percnum;
public String name;
public Instrument(int feedback1, int feedback2, int algo, Operator ... ops) {
this.ops = ops;
@ -58,4 +59,9 @@ public class Instrument {
this.percnum = percnum;
return this;
}
public Instrument setName(String name) {
this.name = name;
return this;
}
}

View file

@ -2,39 +2,54 @@ package client.audio;
import java.util.Arrays;
import common.log.Log;
import common.util.Displayable;
import common.util.Identifyable;
public enum MidiBank implements Identifyable, Displayable {
DMX_DMX("dmx_dmx", "DMX"),
DMX_DOOM1("dmx_doom1", "DMX DOOM I"),
DMX_DOOM2("dmx_doom2", "DMX DOOM II"),
DMX_RAPTOR("dmx_raptor", "DMX Raptor"),
DMX_STRIFE("dmx_strife", "DMX Strife"),
WOLFINSTEIN("wolfinstein", "Wolfenstein"),
STD_O3("std_o3", "SB3 Standard"),
STD_SB("std_sb", "SB Standard"),
HMI_144("hmi_144", "HMI-144"),
CYBERPUCK("cyberpuck", "Cyberpuck"),
D3DTIMBR("d3dtimbr", "D3D"),
D3DTIMBR_MOD("d3dtimbr_mod", "D3D Mod"),
GMOCONEL("gmoconel", "GMOConel"),
GMOPL_MOD("gmopl_mod", "GM Mod"),
SWTIMBR("swtimbr", "SWTimbr"),
TMB_DEFAULT("tmb_default", "TMB"),
WALLENCE("wallence", "Wallence"),
FAT2("fat2", "FatMan 2OP"),
FAT4("fat4", "FatMan 4OP"),
OP2X2("op2x2", "2x2OP"),
WALLACE("wallace", "Wallace"),
EARTHSIEG("earthsieg", "Earthsieg"),
WARCRAFT("warcraft", "Warcraft"),
NEMESIS("nemesis", "Nemesis");
DMX_DMX("dmx_dmx", "op2", "DMX"),
DMX_DOOM1("dmx_doom1", "op2", "DMX DOOM I"),
DMX_DOOM2("dmx_doom2", "op2", "DMX DOOM II"),
DMX_RAPTOR("dmx_raptor", "op2", "DMX Raptor"),
DMX_STRIFE("dmx_strife", "op2", "DMX Strife"),
WOLFINSTEIN("wolfinstein", "op2", "Wolfenstein"),
STD_O3("std_o3", "std_drums_o3", "o3", "SB3"),
STD_SB("std_sb", "std_drums_sb", "sb", "SB"),
HMI_144("hmi_144", "hmi_drums_144", "bnk", "HMI-144"),
CYBERPUCK("cyberpuck", "tmb", "Cyberpuck"),
D3DTIMBR("d3dtimbr", "tmb", "D3D"),
D3DTIMBR_MOD("d3dtimbr_mod", "tmb", "D3D Mod"),
GMOCONEL("gmoconel", "tmb", "GMOConel"),
GMOPL_MOD("gmopl_mod", "tmb", "GM Mod"),
SWTIMBR("swtimbr", "tmb", "SWTimbr"),
TMB_DEFAULT("tmb_default", "tmb", "TMB"),
WALLENCE("wallence", "tmb", "Wallence"),
FAT2("fat2", "op3", "FatMan 2OP"),
FAT4("fat4", "op3", "FatMan 4OP"),
OP2X2("op2x2", "op3", "2x2OP"),
WALLACE("wallace", "op3", "Wallace"),
EARTHSIEG("earthsieg", "ad", "Earthsieg"),
WARCRAFT("warcraft", "ad", "Warcraft"),
NEMESIS("nemesis", "opl", "Nemesis");
private final String name;
private final String display;
private final String melodic;
private final String percussion;
private final Instrument[] data = new Instrument[256];
public static void loadBanks() {
for(MidiBank bank : values()) {
Log.SOUND.trace("Lade Bank %s", bank);
Instrument[] data = BankLoader.readBank(bank.melodic, bank.percussion, false);
if(data == null)
Arrays.fill(bank.data, new Instrument());
else
System.arraycopy(data, 0, bank.data, 0, bank.data.length);
}
}
/*
static {
init0();
init1();
@ -7157,13 +7172,20 @@ public enum MidiBank implements Identifyable, Displayable {
.perc(90, new Instrument(new Operator(0, 63, 0, 10, 0, 15, 8), new Operator(0, 63, 1, 9, 8, 9, 7).ksr(), false, 0, 0, 7).setFixed(60))
.perc(91, new Instrument(new Operator(1, 63, 1, 15, 0, 15, 4).ksl(3).vibrato(), new Operator(9, 63, 3, 15, 0, 15, 8), false, 0, 0, 7).setFixed(60));
}
*/
private MidiBank(String name, String display) {
private MidiBank(String name, String percussion, String extension, String display) {
this.name = name;
this.display = display;
this.melodic = "banks/" + name + "." + extension;
this.percussion = percussion == null ? null : "banks/" + percussion + "." + extension;
Arrays.fill(this.data, new Instrument());
}
private MidiBank(String name, String extension, String display) {
this(name, null, extension, display);
}
private MidiBank instr(int id, Instrument instr) {
this.data[id] = instr;
return this;

View file

@ -17,6 +17,23 @@ public class Operator {
public int offset;
public int detune;
Operator(int mult, int level, int waveform, int a, int d, int s, int r, boolean tremolo, boolean vibrato, boolean sustaining, boolean ksr, int ksl, int offset, int detune) {
this.mult = mult;
this.level = level;
this.waveform = waveform;
this.attack = a;
this.decay = d;
this.sustain = s;
this.release = r;
this.tremolo = tremolo;
this.vibrato = vibrato;
this.sustaining = sustaining;
this.ksr = ksr;
this.ksl = ksl;
this.offset = offset;
this.detune = detune;
}
public Operator(int mult, int level, int waveform, int a, int d, int s, int r) {
this.mult = mult;
this.level = 63 - level;

View file

@ -117,11 +117,11 @@ public class SoundManager {
return CodecJOrbis.readAll(in);
}
catch(FileNotFoundException e) {
Log.IO.error("Fehler beim Lesen von OPUS-Datei '%s': Datei nicht gefunden", filename);
Log.IO.error("Fehler beim Lesen von OGG-Datei '%s': Datei nicht gefunden", filename);
return null;
}
catch(Exception e) {
Log.IO.error("Fehler beim Lesen von OPUS-Datei '%s': %s", filename, e.getMessage());
Log.IO.error("Fehler beim Lesen von OGG-Datei '%s': %s", filename, e.getMessage());
return null;
}
finally {

View file

@ -0,0 +1,100 @@
package client.audio;
public class WavWriter {
/*
static const char *wav_hdr = "RIFF";
static const char *wav_hdr_fmt = "fmt ";
static const char *wav_hdr_data = "data";
static const char *wav_format = "WAVE";
#define WAV_HDRSIZE 44
#define STR_WAV_OPNERR "Fehler beim Oeffnen von WAV-Datei '%s': %s (%d)"
#define STR_WAV_WRITERR "Fehler beim Schreiben nach WAV-Datei '%s': "
#define STR_WAV_EIO STR_WAV_WRITERR "E/A-Fehler"
#define STR_WAV_EGEN STR_WAV_WRITERR "%s (%d)"
typedef struct {
uint32_t samplerate;
uint16_t channels;
uint16_t bytes;
uint32_t samples;
FILE *fd;
const char *filename;
uint8_t *buffer;
} wav_handle;
void wav_write_uint32(uint8_t *data, uint32_t value) {
for(int h = 0; h < 4; h++) {
data[h] = ((uint32_t)((value >> (8*h) & 0xff)));
}
}
void wav_write_uint16(uint8_t *data, uint16_t value) {
for(int h = 0; h < 2; h++) {
data[h] = ((uint16_t)((value >> (8*h) & 0xff)));
}
}
void wav_write_header(uint8_t *data, uint32_t samplerate, uint16_t channels, uint32_t samples, uint16_t bytes) {
memcpy(data+0, wav_hdr, 4);
wav_write_uint32(data+4, 36 + samples * ((uint32_t)channels) * ((uint32_t)bytes));
memcpy(data+8, wav_format, 4);
memcpy(data+12, wav_hdr_fmt, 4);
wav_write_uint32(data+16, 16);
wav_write_uint16(data+20, 1);
wav_write_uint16(data+22, channels);
wav_write_uint32(data+24, samplerate);
wav_write_uint32(data+28, samplerate * ((uint32_t)channels) * ((uint32_t)bytes));
wav_write_uint16(data+32, channels * bytes);
wav_write_uint16(data+34, 8 * bytes);
memcpy(data+36, wav_hdr_data, 4);
wav_write_uint32(data+40, samples * ((uint32_t)channels) * ((uint32_t)bytes));
}
bool wav_open(wav_handle *wav, const char *filename, uint32_t samplerate, uint16_t channels, uint16_t bytes) {
int err;
FILE *fd = fopen(filename, "wb");
if(fd == NULL) {
err = errno;
mid_log(STR_WAV_OPNERR, filename, strerror(err), err);
return false;
}
uint8_t pad[WAV_HDRSIZE];
memset(pad, 0, WAV_HDRSIZE);
if(fwrite(pad, 1, WAV_HDRSIZE, fd) != WAV_HDRSIZE) {
mid_log(STR_WAV_EIO, filename);
fclose(fd);
return false;
}
wav->fd = fd;
wav->samplerate = samplerate;
wav->channels = channels;
wav->bytes = bytes;
wav->samples = 0;
wav->filename = filename;
return true;
}
bool wav_close(wav_handle *wav) {
if(wav->fd == NULL) {
return false;
}
int err;
if(fseek(wav->fd, 0L, SEEK_SET)) {
err = errno;
mid_log(STR_WAV_EGEN, wav->filename, strerror(err), err);
fclose(wav->fd);
return false;
}
uint8_t header[WAV_HDRSIZE];
wav_write_header(header, wav->samplerate, wav->channels, wav->samples, wav->bytes);
if(fwrite(header, 1, WAV_HDRSIZE, wav->fd) != WAV_HDRSIZE) {
mid_log(STR_WAV_EIO, wav->filename);
fclose(wav->fd);
return false;
}
fclose(wav->fd);
return true;
}
*/
}

View file

@ -12,17 +12,15 @@ import java.nio.charset.Charset;
public class FileUtils {
public static final Charset UTF_8 = Charset.forName("UTF-8");
private static String read(InputStream in) throws IOException {
String s;
private static byte[] read(InputStream in) throws IOException {
ByteArrayOutputStream output = new ByteArrayOutputStream();
try {
ByteArrayOutputStream output = new ByteArrayOutputStream();
byte[] buffer = new byte[4096];
long count = 0L;
int n;
for(boolean u = false; -1 != (n = in.read(buffer)); count += (long)n) {
output.write(buffer, 0, n);
}
s = new String(output.toByteArray(), UTF_8);
}
finally {
try {
@ -32,14 +30,18 @@ public class FileUtils {
catch(IOException e) {
}
}
return s;
return output.toByteArray();
}
public static String read(File file) throws IOException {
return read(new FileInputStream(file));
return new String(read(new FileInputStream(file)), UTF_8);
}
public static String read(String resource) throws IOException {
return new String(read(getResource(resource)), UTF_8);
}
public static byte[] readBytes(String resource) throws IOException {
return read(getResource(resource));
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.