diff --git a/client/src/main/java/client/audio/BankLoader.java b/client/src/main/java/client/audio/BankLoader.java index 8893afa4..e4cae516 100644 --- a/client/src/main/java/client/audio/BankLoader.java +++ b/client/src/main/java/client/audio/BankLoader.java @@ -9,50 +9,7 @@ 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_EEOD "Fehler beim Verarbeiten von Bank-Datei '%s': Ende der Daten erreicht" - +public abstract class BankLoader { 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) { @@ -95,15 +52,6 @@ typedef struct { } 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; @@ -161,7 +109,7 @@ typedef struct { while(len < 32 && data[offset + len] != 0) { ++len; } - ins.setName(new String(data, offset, len)); + ins.setName(new String(data, offset, len).trim()); offset += 32; } return instr; @@ -204,468 +152,289 @@ typedef struct { return instr; } - /* - private static Instrument sb_read_instr(bank_instr *instr, uint8_t *data, uint8_t drum) { + private static Instrument sb_read_instr(byte[] data, int offset, boolean drum) { + char[] name = new char[28]; for(int h = 0; h < 28; h++) { - instr->name[h] = (data[h] == 0x1a) ? ' ' : data[h]; + name[h] = (data[offset + h] == 0x1a) ? ' ' : (char)data[offset + h]; } - instr->name[28] = 0; - instr->percnum = data[35] & 0x7f; - instr->fixed = drum; - instr->op = b_op2; - data += 36; + int percnum = data[offset + 35] & 0x7f; + offset += 36; + Operator[] ops = new Operator[2]; 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; + boolean tremolo = (data[offset + op+0] & 0x80) != 0; + boolean vibrato = (data[offset + op+0] & 0x40) != 0; + boolean sustaining = (data[offset + op+0] & 0x20) != 0; + boolean ksr = (data[offset + op+0] & 0x10) != 0; + int mult = data[offset + op+0] & 0x0f; + int attack = ((data[offset + op+4] & 255) >> 4) & 0x0f; + int decay = data[offset + op+4] & 0x0f; + int sustain = ((data[offset + op+6] & 255) >> 4) & 0x0f; + int release = data[offset + op+6] & 0x0f; + int waveform = data[offset + op+8] & 0x07; + int ksl = ((data[offset + op+2] & 255) >> 6) & 0x03; + int level = data[offset + op+2] & 0x3f; + ops[op] = new Operator(mult, level, waveform, attack, decay, sustain, release, tremolo, vibrato, sustaining, ksr, ksl, 0, 0); } - 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; + Instrument ins = new Instrument((data[offset + 10] >> 1) & 0x07, 0, data[offset + 10] & 0x01, ops); + if(drum) + ins.setFixed(percnum); + ins.setName(new String(name).trim()); + return ins; } private static Instrument[] sb_read_bank(byte[] raw, String filename, boolean drum) { - uint8_t *data; - bank_instr *instr; - uint32_t size = bnk_read_sbank(&data, &instr, filename, 128*52); - if(size == 0) { - return NULL; + byte[] data = bnk_read_sbank(raw, filename, 128 * 52); + if(data == null) + return null; + Instrument[] instr = new Instrument[256]; + for(int i = 0; i < instr.length; i++) { + instr[i] = new Instrument(); } - uint8_t *odata = data; + int offset = 0; for(int i = 0; i < 128; i++) { - instr[i + (drum ? 0 : 128)].op = b_op0; - instr[i + (drum ? 0 : 128)].name[0] = 0; + instr[i + (drum ? 128 : 0)] = sb_read_instr(data, offset, drum); + offset += 52; } - for(int i = 0; i < 128; i++) { - sb_read_instr(&instr[i + (drum ? 128 : 0)], data, drum); - data += 52; - } - free(odata); return instr; } - private static Instrument sb3_read_instr(bank_instr *instr, uint8_t *data, uint8_t drum) { + private static Instrument sb3_read_instr(byte[] data, int offset, boolean drum) { + char[] name = new char[28]; for(int h = 0; h < 28; h++) { - instr->name[h] = (data[h] == 0x1a) ? ' ' : data[h]; + name[h] = (data[offset + h] == 0x1a) ? ' ' : (char)data[offset + 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++) { + int percnum = data[offset + 35] & 0x7f; + boolean op4 = data[offset + 0] == '4'; + offset += 36; + Operator[] ops = new Operator[op4 ? 4 : 2]; + int[] fb = new int[2]; + int algo = op4 ? 0x04 : 0x00; + for(int ch = 0; ch < (op4 ? 2 : 1); 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; + boolean tremolo = (data[offset + op+0] & 0x80) != 0; + boolean vibrato = (data[offset + op+0] & 0x40) != 0; + boolean sustaining = (data[offset + op+0] & 0x20) != 0; + boolean ksr = (data[offset + op+0] & 0x10) != 0; + int mult = data[offset + op+0] & 0x0f; + int attack = ((data[offset + op+4] & 255) >> 4) & 0x0f; + int decay = data[offset + op+4] & 0x0f; + int sustain = ((data[offset + op+6] & 255) >> 4) & 0x0f; + int release = data[offset + op+6] & 0x0f; + int waveform = data[offset + op+8] & 0x07; + int ksl = ((data[offset + op+2] & 255) >> 6) & 0x03; + int level = data[offset + op+2] & 0x3f; + ops[ch * 2 + op] = new Operator(mult, level, waveform, attack, decay, sustain, release, tremolo, vibrato, sustaining, ksr, ksl, 0, 0); } - 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; + fb[ch] = (data[offset + 10] >> 1) & 0x07; + algo |= op4 ? (data[offset + 10] & 0x01) << (1 - ch) : data[offset + 10] & 0x01; + offset += 11; } + Instrument ins = new Instrument(fb[0], fb[1], algo, ops); + if(drum) + ins.setFixed(percnum); + ins.setName(new String(name).trim()); + return ins; } private static Instrument[] sb3_read_bank(byte[] raw, String filename, boolean drum) { - uint8_t *data; - bank_instr *instr; - uint32_t size = bnk_read_sbank(&data, &instr, filename, 128*60); - if(size == 0) { - return NULL; + byte[] data = bnk_read_sbank(raw, filename, 128*60); + if(data == null) + return null; + Instrument[] instr = new Instrument[256]; + for(int i = 0; i < instr.length; i++) { + instr[i] = new Instrument(); } - uint8_t *odata = data; + int offset = 0; for(int i = 0; i < 128; i++) { - instr[i + (drum ? 0 : 128)].op = b_op0; - instr[i + (drum ? 0 : 128)].name[0] = 0; + instr[i + (drum ? 128 : 0)] = sb3_read_instr(data, offset, drum); + offset += 60; } - for(int i = 0; i < 128; i++) { - sb3_read_instr(&instr[i + (drum ? 128 : 0)], data, drum); - data += 60; - } - free(odata); return instr; } - private static Instrument 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++) { + private static Instrument op3_read_instr(byte[] data, int offset, boolean drum) { + int percnum = data[offset + 1] & 0x7f; + boolean op4 = (data[offset + 0] & 0x01) != 0; + offset += 2; + Operator[] ops = new Operator[op4 ? 4 : 2]; + int[] fb = new int[2]; + int algo = op4 ? 0x04 : 0x00; + for(int ch = 0; ch < (op4 ? 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; + boolean tremolo = (data[offset + op*6+0] & 0x80) != 0; + boolean vibrato = (data[offset + op*6+0] & 0x40) != 0; + boolean sustaining = (data[offset + op*6+0] & 0x20) != 0; + boolean ksr = (data[offset + op*6+0] & 0x10) != 0; + int mult = data[offset + op*6+0] & 0x0f; + int attack = ((data[offset + op*6+2] & 255) >> 4) & 0x0f; + int decay = data[offset + op*6+2] & 0x0f; + int sustain = ((data[offset + op*6+3] & 255) >> 4) & 0x0f; + int release = data[offset + op*6+3] & 0x0f; + int waveform = data[offset + op*6+4] & 0x07; + int ksl = ((data[offset + op*6+1] & 255) >> 6) & 0x03; + int level = data[offset + op*6+1] & 0x3f; + ops[ch * 2 + op] = new Operator(mult, level, waveform, attack, decay, sustain, release, tremolo, vibrato, sustaining, ksr, ksl, 0, 0); } - 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; + fb[ch] = (data[offset + 5] >> 1) & 0x07; + algo |= op4 ? (data[offset + 5] & 0x01) << (1 - ch) : data[offset + 5] & 0x01; + offset += 11; } + Instrument ins = new Instrument(fb[0], fb[1], algo, ops); + if(drum) + ins.setFixed(percnum); + return ins; } private static Instrument[] op3_read_bank(byte[] raw, String 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; + byte[] data = bnk_read_mhbank(raw, filename, 16, 256 * 24 + 16, "Junglevision Patch File\u001a".getBytes()); + if(data == null) + return null; + Instrument[] instr = new Instrument[256]; + for(int i = 0; i < instr.length; i++) { + instr[i] = new Instrument(); } - 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; + int offset = 8; + int nmelo = dmx_read_uint16(data, offset + 0); + int ndrum = dmx_read_uint16(data, offset + 2); + int omelo = dmx_read_uint16(data, offset + 4); + int odrum = dmx_read_uint16(data, offset + 6); + offset += 8; + if((nmelo + ndrum) * 24 + 16 > data.length || omelo + nmelo > 128 || odrum + ndrum > 128) { + Log.SOUND.error("Fehler beim Verarbeiten von Bank-Datei '%s': Ende der Daten erreicht", filename); + return null; } for(int i = 0; i < nmelo; i++) { - op3_read_instr(&instr[i + omelo], data, 0); - data += 24; + instr[i + omelo] = op3_read_instr(data, offset, false); + offset += 24; } for(int i = 0; i < ndrum; i++) { - op3_read_instr(&instr[i + odrum + 128], data, 1); - data += 24; + instr[i + odrum + 128] = op3_read_instr(data, offset, true); + offset += 24; } - free(odata); return instr; } - private static Instrument 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++) { + private static Instrument ad_read_instr(byte[] data, int offset, boolean drum, int isize) { + if(isize < 12) + return new Instrument(); + int percnum = data[offset + 0] & 0x7f; + boolean op4 = isize >= 23; + offset += 1; + int feedback = (data[offset + 5] >> 1) & 0x07; + int algo = op4 ? 0x04 | (data[offset + 5] & 0x01) << 1 | ((data[offset + 5] & 0x80) != 0 ? 1 : 0) : data[offset + 5] & 0x01; + Operator[] ops = new Operator[op4 ? 4 : 2]; + for(int ch = 0; ch < (op4 ? 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; + boolean tremolo = (data[offset + op*6+0] & 0x80) != 0; + boolean vibrato = (data[offset + op*6+0] & 0x40) != 0; + boolean sustaining = (data[offset + op*6+0] & 0x20) != 0; + boolean ksr = (data[offset + op*6+0] & 0x10) != 0; + int mult = data[offset + op*6+0] & 0x0f; + int attack = ((data[offset + op*6+2] & 255) >> 4) & 0x0f; + int decay = data[offset + op*6+2] & 0x0f; + int sustain = ((data[offset + op*6+3] & 255) >> 4) & 0x0f; + int release = data[offset + op*6+3] & 0x0f; + int waveform = data[offset + op*6+4] & 0x07; + int ksl = ((data[offset + op*6+1] & 255) >> 6) & 0x03; + int level = data[offset + op*6+1] & 0x3f; + ops[ch * 2 + op] = new Operator(mult, level, waveform, attack, decay, sustain, release, tremolo, vibrato, sustaining, ksr, ksl, 0, 0); } - instr->channels[ch].offset = 0; - instr->channels[ch].detune = 0; - data += 11; + offset += 11; } + Instrument ins = new Instrument(feedback, 0, algo, ops); + if(drum) + ins.setFixed(percnum); + return ins; } private static Instrument[] ad_read_bank(byte[] raw, String 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; + byte[] data = bnk_read_mbank(raw, filename, 2, 256 * 20 + 2); + if(data == null) + return null; + Instrument[] instr = new Instrument[256]; + for(int i = 0; i < instr.length; i++) { + instr[i] = new Instrument(); } - 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; + int offset = 0; + for(int i = 0;; i++, offset += 6) { + if(i * 6 >= data.length) { + Log.SOUND.error("Fehler beim Verarbeiten von Bank-Datei '%s': Ende der Daten erreicht", filename); + return null; } - uint8_t prog = data[0]; - if(prog == 0xff) { + int prog = data[offset + 0] & 255; + if(prog == 0xff) break; - } - if(prog >= 128) { + if(prog >= 128) continue; - } - uint8_t bank = data[1]; - if((bank != 0) && (bank != 127)) { + int bank = data[offset + 1] & 255; + if(bank != 0 && bank != 127) continue; + int offs = dmx_read_uint16(data, offset + 2); + int isize; + if(offs + 2 > data.length || offs + (isize = dmx_read_uint16(data, offs)) > data.length || isize < 2) { + Log.SOUND.error("Fehler beim Verarbeiten von Bank-Datei '%s': Ende der Daten erreicht", filename); + return null; } - 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); + instr[prog + (bank == 127 ? 128 : 0)] = ad_read_instr(data, offs + 2, bank == 127, isize - 2); } - free(odata); return instr; } - private static Instrument bk_read_instr(bank_instr *instr, uint8_t *data, uint8_t drum) { - instr->fixed = drum; - instr->op = b_op2; + private static Instrument bk_read_instr(byte[] data, int offset, boolean drum, int percnum) { + Operator[] ops = new Operator[2]; 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; + boolean tremolo = (data[offset + op*13+9] & 0x01) != 0; + boolean vibrato = (data[offset + op*13+10] & 0x01) != 0; + boolean sustaining = (data[offset + op*13+5] & 0x01) != 0; + boolean ksr = (data[offset + op*13+11] & 0x01) != 0; + int mult = data[offset + op*13+1] & 0x0f; + int attack = data[offset + op*13+3] & 0x0f; + int decay = data[offset + op*13+6] & 0x0f; + int sustain = data[offset + op*13+4] & 0x0f; + int release = data[offset + op*13+7] & 0x0f; + int waveform = data[offset + 26+op] & 0x07; + int ksl = data[offset + op*13+0] & 0x03; + int level = data[offset + op*13+8] & 0x3f; + ops[op] = new Operator(mult, level, waveform, attack, decay, sustain, release, tremolo, vibrato, sustaining, ksr, ksl, 0, 0); } - 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; + Instrument ins = new Instrument(data[offset + 2] & 0x07, 0, (data[offset + 25] & 0x01) ^ 1, ops); + if(drum) + ins.setFixed(percnum); + return ins; } private static Instrument[] bk_read_bank(byte[] raw, String filename, boolean 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; + byte[] data = bnk_read_mbank(raw, filename, 28, 256 * 42 + 28); + if(data == null) + return null; + if(!Arrays.equals(data, 2, 2 + 6, "ADLIB-".getBytes(), 0, 6)) { + Log.SOUND.error("Fehler beim Lesen von Bank-Datei '%s': Fehlerhafter Dateiheader oder falscher Dateityp", filename); + 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; + Instrument[] instr = new Instrument[256]; + for(int i = 0; i < instr.length; i++) { + instr[i] = new Instrument(); } - data += 8; - for(int i = 0; i < 256; i++) { - instr[i].op = b_op0; - instr[i].name[0] = 0; + int offset = 8; + int ninst = dmx_read_uint16(data, offset + 2); + offset += 20; + if(ninst * 42 + 28 > data.length) { + Log.SOUND.error("Fehler beim Verarbeiten von Bank-Datei '%s': Ende der Daten erreicht", filename); + return null; } - // 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; + offset += ninst * 12; int pos = 0; - for(int i = 0; i < ninst; i++, data += 30) { - if(data[0] != 0) { + for(int i = 0; i < ninst; i++, offset += 30) { + if(data[offset + 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) { + int ndata = i * 12 + 28; + instr[pos + (drum ? 128 : 0)] = bk_read_instr(data, offset + 2, drum, data[ndata + 2] & 0x7f); + instr[pos + (drum ? 128 : 0)].setName(new String(data, ndata + 3, 8).trim()); + if(++pos == 128) break; - } } - free(odata); 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(ext.equalsIgnoreCase("dmx") || ext.equalsIgnoreCase("op2") || ext.equalsIgnoreCase("lmp")) { - return dmx_read_bank(raw, name); - } - else if(ext.equalsIgnoreCase("tmb")) { - return tmb_read_bank(raw, name); - } -// else if(ext.equalsIgnoreCase("sb")) { -// return sb_read_bank(raw, name, drum); -// } -// else if(ext.equalsIgnoreCase("o3")) { -// return sb3_read_bank(raw, name, drum); -// } -// else if(ext.equalsIgnoreCase("op3")) { -// return op3_read_bank(raw, name); -// } -// else if(ext.equalsIgnoreCase("ad") || ext.equalsIgnoreCase("opl")) { -// return ad_read_bank(raw, name); -// } -// else if(ext.equalsIgnoreCase("bnk")) { -// return bk_read_bank(raw, name, drum); -// } - Log.SOUND.error("Format von Bank-Datei '%s' unbekannt", name); - return null; -// else if(strcmp(ext, "skb") == 0) { -// return skb_read_bank(filename); -// } -// else if(strcmp(ext, "ibk") == 0) { -// return ibk_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); - // } - } - - 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; - } - */ /* void ibk_read_instr(bank_instr *instr, uint8_t *data, uint8_t drum) { @@ -774,155 +543,86 @@ typedef struct { 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(ext.equalsIgnoreCase("dmx") || ext.equalsIgnoreCase("op2") || ext.equalsIgnoreCase("lmp")) { + return dmx_read_bank(raw, name); + } + else if(ext.equalsIgnoreCase("tmb")) { + return tmb_read_bank(raw, name); + } + else if(ext.equalsIgnoreCase("sb")) { + return sb_read_bank(raw, name, drum); + } + else if(ext.equalsIgnoreCase("o3")) { + return sb3_read_bank(raw, name, drum); + } + else if(ext.equalsIgnoreCase("op3")) { + return op3_read_bank(raw, name); + } + else if(ext.equalsIgnoreCase("ad") || ext.equalsIgnoreCase("opl")) { + return ad_read_bank(raw, name); + } + else if(ext.equalsIgnoreCase("bnk")) { + return bk_read_bank(raw, name, drum); + } +// else if(ext.equalsIgnoreCase("ibk")) { +// return ibk_read_bank(raw, name, drum); +// } +// else if(ext.equalsIgnoreCase("tim") || ext.equalsIgnoreCase("snd")) { +// return tim_read_bank(raw, name, drum); +// } + 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; + } }