925 lines
29 KiB
C
925 lines
29 KiB
C
|
|
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;
|
|
|
|
uint32_t bnk_read_mhbank(uint8_t **data, bank_instr **instr, const char *filename, uint32_t minsize, uint32_t maxsize, const char *hdr, uint32_t hdrsize) {
|
|
int err;
|
|
FILE *fd = fopen(filename, "rb");
|
|
if(fd == NULL) {
|
|
err = errno;
|
|
fprintf(stderr, STR_BNK_OPNERR"\n", filename, strerror(err), err);
|
|
return 0;
|
|
}
|
|
if(fseek(fd, 0L, SEEK_END)) {
|
|
err = errno;
|
|
fprintf(stderr, STR_BNK_EGEN"\n", filename, strerror(err), err);
|
|
fclose(fd);
|
|
return 0;
|
|
}
|
|
long size = ftell(fd);
|
|
if(size < 0L) {
|
|
err = errno;
|
|
fprintf(stderr, STR_BNK_EGEN"\n", filename, strerror(err), err);
|
|
fclose(fd);
|
|
return 0;
|
|
}
|
|
if(fseek(fd, 0L, SEEK_SET)) {
|
|
err = errno;
|
|
fprintf(stderr, STR_BNK_EGEN"\n", filename, strerror(err), err);
|
|
fclose(fd);
|
|
return 0;
|
|
}
|
|
if(size < (hdrsize+minsize)) {
|
|
fprintf(stderr, STR_BNK_ESHORT"\n", filename);
|
|
fclose(fd);
|
|
return 0;
|
|
}
|
|
if(hdrsize > 0) {
|
|
uint8_t header[hdrsize];
|
|
if(fread(header, 1, hdrsize, fd) != hdrsize) {
|
|
err = feof(fd);
|
|
fprintf(stderr, err == 0 ? STR_BNK_EIO"\n" : STR_BNK_EEOF"\n", filename);
|
|
fclose(fd);
|
|
return 0;
|
|
}
|
|
if(memcmp(header, hdr, hdrsize) != 0) {
|
|
fprintf(stderr, STR_BNK_EMFHDR"\n", filename);
|
|
fclose(fd);
|
|
return 0;
|
|
}
|
|
size -= hdrsize;
|
|
}
|
|
size = ((maxsize > 0) && (size > maxsize)) ? maxsize : size;
|
|
*data = malloc(size);
|
|
if(fread(*data, 1, size, fd) != size) {
|
|
err = feof(fd);
|
|
fprintf(stderr, err == 0 ? STR_BNK_EIO"\n" : STR_BNK_EEOF"\n", filename);
|
|
fclose(fd);
|
|
free(*data);
|
|
return 0;
|
|
}
|
|
fclose(fd);
|
|
*instr = malloc(sizeof(bank_instr)*256);
|
|
return size;
|
|
}
|
|
|
|
uint32_t bnk_read_mbank(uint8_t **data, bank_instr **instr, const char *filename, uint32_t minsize, uint32_t maxsize) {
|
|
return bnk_read_mhbank(data, instr, filename, minsize, maxsize, NULL, 0);
|
|
}
|
|
|
|
uint32_t bnk_read_hbank(uint8_t **data, bank_instr **instr, const char *filename, uint32_t size, const char *hdr, uint32_t hdrsize) {
|
|
return bnk_read_mhbank(data, instr, filename, size, size, hdr, hdrsize);
|
|
}
|
|
|
|
uint32_t bnk_read_sbank(uint8_t **data, bank_instr **instr, const char *filename, uint32_t size) {
|
|
return bnk_read_mhbank(data, instr, filename, size, size, NULL, 0);
|
|
}
|
|
|
|
uint16_t dmx_read_uint16(uint8_t *data) {
|
|
uint16_t value = 0;
|
|
for(int h = 0; h < 2; h++) {
|
|
value |= ((uint16_t)data[1-h]);
|
|
value <<= h < 1 ? 8 : 0;
|
|
}
|
|
return value;
|
|
}
|
|
|
|
uint16_t dmx_read_uint16be(uint8_t *data) {
|
|
uint16_t value = 0;
|
|
for(int h = 0; h < 2; h++) {
|
|
value |= ((uint16_t)data[h]);
|
|
value <<= h < 1 ? 8 : 0;
|
|
}
|
|
return value;
|
|
}
|
|
|
|
void dmx_read_instr(bank_instr *instr, uint8_t *data, uint8_t drum) {
|
|
instr->fixed = ((data[0] & 0x01) > 0) | drum;
|
|
instr->op = ((data[0] & 0x04) > 0) ? b_op22 : b_op2;
|
|
instr->channels[0].detune = 0;
|
|
instr->channels[1].detune = ((int16_t)data[2]) - 128;
|
|
instr->percnum = data[3] & 0x7f;
|
|
data += 4;
|
|
for(int ch = 0; ch < 2; ch++) {
|
|
for(int op = 0; op < 2; op++) {
|
|
instr->channels[ch].ops[op].tremolo = (data[op*7+0] & 0x80) > 0;
|
|
instr->channels[ch].ops[op].vibrato = (data[op*7+0] & 0x40) > 0;
|
|
instr->channels[ch].ops[op].sustaining = (data[op*7+0] & 0x20) > 0;
|
|
instr->channels[ch].ops[op].ksr = (data[op*7+0] & 0x10) > 0;
|
|
instr->channels[ch].ops[op].mult = data[op*7+0] & 0x0f;
|
|
instr->channels[ch].ops[op].attack = (data[op*7+1] >> 4) & 0x0f;
|
|
instr->channels[ch].ops[op].decay = data[op*7+1] & 0x0f;
|
|
instr->channels[ch].ops[op].sustain = (data[op*7+2] >> 4) & 0x0f;
|
|
instr->channels[ch].ops[op].release = data[op*7+2] & 0x0f;
|
|
instr->channels[ch].ops[op].waveform = data[op*7+3] & 0x07;
|
|
instr->channels[ch].ops[op].ksl = (data[op*7+4] >> 6) & 0x03;
|
|
instr->channels[ch].ops[op].level = data[op*7+5] & 0x3f;
|
|
}
|
|
instr->channels[ch].feedback = (data[6] >> 1) & 0x07;
|
|
instr->channels[ch].am = data[6] & 0x01;
|
|
instr->channels[ch].offset = ((int16_t)dmx_read_uint16(data+14)) + 12;
|
|
data += 16;
|
|
}
|
|
}
|
|
|
|
bank_instr *dmx_read_bank(const char *filename) {
|
|
uint8_t *data;
|
|
bank_instr *instr;
|
|
uint32_t size = bnk_read_hbank(&data, &instr, filename, 175*68, "#OPL_II#", 8);
|
|
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 < 175; i++) {
|
|
dmx_read_instr(&instr[(i < 128) ? i : (i + 35)], data, i >= 128);
|
|
data += 36;
|
|
}
|
|
for(int i = 0; i < 175; i++) {
|
|
bank_instr *ins = &instr[(i < 128) ? i : (i + 35)];
|
|
memcpy(ins->name, data, 32);
|
|
ins->name[31] = 0;
|
|
data += 32;
|
|
}
|
|
free(odata);
|
|
return instr;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
bank_instr *bnk_read_bank(const char *filename, uint8_t drum) {
|
|
int len = 0;
|
|
int dp = 0;
|
|
char ch;
|
|
while(ch = filename[len++]) {
|
|
if(ch == '.') {
|
|
dp = len;
|
|
}
|
|
}
|
|
if(dp == 0) {
|
|
fprintf(stderr, STR_BNK_UNKN"\n", filename);
|
|
return NULL;
|
|
}
|
|
char ext[len -= dp];
|
|
for(int c = 0; c < len; c++) {
|
|
ext[c] = filename[dp+c];
|
|
if((ext[c] >= 'A') && (ext[c] <= 'Z')) {
|
|
ext[c] = ext[c] - 'A' + 'a';
|
|
}
|
|
}
|
|
if(strcmp(ext, "skb") == 0) {
|
|
return skb_read_bank(filename);
|
|
}
|
|
else if((strcmp(ext, "dmx") == 0) || (strcmp(ext, "op2") == 0) || (strcmp(ext, "lmp") == 0)) {
|
|
return dmx_read_bank(filename);
|
|
}
|
|
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);
|
|
// }
|
|
fprintf(stderr, STR_BNK_UNKN"\n", filename);
|
|
return NULL;
|
|
}
|
|
|
|
bank_instr *bnk_read_banks(const char *filename, const char *drumname, uint8_t usedrum) {
|
|
bank_instr *ins1 = bnk_read_bank(filename, usedrum);
|
|
if((ins1 != NULL) && (drumname != NULL)) {
|
|
bank_instr *ins2 = bnk_read_bank(drumname, usedrum ^ 1);
|
|
if(ins2 != NULL) {
|
|
memcpy(ins1+128, ins2+128, sizeof(bank_instr)*128);
|
|
free(ins2);
|
|
}
|
|
else {
|
|
free(ins1);
|
|
ins1 = NULL;
|
|
}
|
|
}
|
|
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;
|
|
}
|