package game.audio; public class Midi { /* * * byte mid_nowait; byte mid_bank; byte mid_keep; byte mid_unknown; byte mid_visual; int mid_velo; int mid_voices; * #define BANK_MAX 64 #define MID_DEFTEMPO 500000 #define BANK_KEEP 0x01 #define BANK_UNKN 0x02 #define BANK_PBRANGE 2.0 #define RSM_FRAC 10 #define BANK_VELOFUNC(x, n) (1.0-log(1.0+((1.0-pow(x,n))*(M_E-1.0)))) // input: [0, 256), output: [0, 65536] #define OPL_SIN(x) ((int)(sin((x) * M_PI / 512.0) * 65536.0)) enum mid_event { midev_noteoff = 0x80, midev_noteon = 0x90, midev_aftertouch = 0xa0, midev_control = 0xb0, midev_progchg = 0xc0, midev_chnpressure = 0xd0, midev_pitchbend = 0xe0, midev_sysex = 0xf0, midev_songpos = 0xf2, midev_songsel = 0xf3, midev_tunereq = 0xf6, midev_endsysex = 0xf7, midev_clock = 0xf8, midev_start = 0xfa, midev_continue = 0xfb, midev_stop = 0xfc, midev_actsense = 0xfe, midev_meta = 0xff }; enum mid_meta { midmt_seqnum = 0x00, // nn nn midmt_text = 0x01, // text... midmt_copyright = 0x02, // text... midmt_trackname = 0x03, // text... midmt_instrname = 0x04, // text... midmt_lyric = 0x05, // text... midmt_marker = 0x06, // text... midmt_cuepoint = 0x07, // text... midmt_chnprefix = 0x20, // cc midmt_endtrack = 0x2f, // midmt_tempo = 0x51, // tt tt tt midmt_smpte = 0x54, // hr mn se fr ff midmt_timesig = 0x58, // nn dd cc bb midmt_keysig = 0x59, // sf mi midmt_seqspec = 0x7f // data... }; enum bank_op { b_op2, b_op4, b_op22, b_op0 }; enum opl3_op { ch_2op = 0, ch_4op = 1, ch_4op2 = 2 }; enum envelope_gen_num { envelope_gen_num_attack = 0, envelope_gen_num_decay = 1, envelope_gen_num_sustain = 2, envelope_gen_num_release = 3 }; static const char *mid_hdr = "MThd"; static const char *mid_trk = "MTrk"; static const uint bank_notes[] = { 8175, 8661, 9177, 9722, 10300, 10913, 11562, 12249, 12978, 13750, 14567, 15433, 16351, 17323, 18354, 19445, 20601, 21826, 23124, 24499, 25956, 27500, 29135, 30867, 32703, 34647, 36708, 38890, 41203, 43653, 46249, 48999, 51913, 55000, 58270, 61735, 65406, 69295, 73416, 77781, 82406, 87307, 92498, 97998, 103826, 110000, 116540, 123470, 130812, 138591, 146832, 155563, 164813, 174614, 184997, 195997, 207652, 220000, 233081, 246941, 261625, 277182, 293664, 311126, 329627, 349228, 369994, 391995, 415304, 440000, 466163, 493883, 523251, 554365, 587329, 622253, 659255, 698456, 739988, 783990, 830609, 880000, 932327, 987766, 1046502, 1108730, 1174659, 1244507, 1318510, 1396912, 1479977, 1567981, 1661218, 1760000, 1864655, 1975533, 2093004, 2217461, 2349318, 2489015, 2637020, 2793825, 2959955, 3135963, 3322437, 3520000, 3729310, 3951066, 4186009, 4434922, 4698636, 4978031, 5274040, 5587651, 5919910, 6271926, 6644875, 7040000, 7458620, 7902132, 8372018, 8869844, 9397272, 9956063, 10548081, 11175303, 11839821, 12543853 }; static const uint opl3_maxfreq[] = { 48503, 97006, 194013, 388026, 776053, 1552107, 3104215, 6208431 }; static const ushort logsinrom[256] = { 0x859, 0x6c3, 0x607, 0x58b, 0x52e, 0x4e4, 0x4a6, 0x471, 0x443, 0x41a, 0x3f5, 0x3d3, 0x3b5, 0x398, 0x37e, 0x365, 0x34e, 0x339, 0x324, 0x311, 0x2ff, 0x2ed, 0x2dc, 0x2cd, 0x2bd, 0x2af, 0x2a0, 0x293, 0x286, 0x279, 0x26d, 0x261, 0x256, 0x24b, 0x240, 0x236, 0x22c, 0x222, 0x218, 0x20f, 0x206, 0x1fd, 0x1f5, 0x1ec, 0x1e4, 0x1dc, 0x1d4, 0x1cd, 0x1c5, 0x1be, 0x1b7, 0x1b0, 0x1a9, 0x1a2, 0x19b, 0x195, 0x18f, 0x188, 0x182, 0x17c, 0x177, 0x171, 0x16b, 0x166, 0x160, 0x15b, 0x155, 0x150, 0x14b, 0x146, 0x141, 0x13c, 0x137, 0x133, 0x12e, 0x129, 0x125, 0x121, 0x11c, 0x118, 0x114, 0x10f, 0x10b, 0x107, 0x103, 0x0ff, 0x0fb, 0x0f8, 0x0f4, 0x0f0, 0x0ec, 0x0e9, 0x0e5, 0x0e2, 0x0de, 0x0db, 0x0d7, 0x0d4, 0x0d1, 0x0cd, 0x0ca, 0x0c7, 0x0c4, 0x0c1, 0x0be, 0x0bb, 0x0b8, 0x0b5, 0x0b2, 0x0af, 0x0ac, 0x0a9, 0x0a7, 0x0a4, 0x0a1, 0x09f, 0x09c, 0x099, 0x097, 0x094, 0x092, 0x08f, 0x08d, 0x08a, 0x088, 0x086, 0x083, 0x081, 0x07f, 0x07d, 0x07a, 0x078, 0x076, 0x074, 0x072, 0x070, 0x06e, 0x06c, 0x06a, 0x068, 0x066, 0x064, 0x062, 0x060, 0x05e, 0x05c, 0x05b, 0x059, 0x057, 0x055, 0x053, 0x052, 0x050, 0x04e, 0x04d, 0x04b, 0x04a, 0x048, 0x046, 0x045, 0x043, 0x042, 0x040, 0x03f, 0x03e, 0x03c, 0x03b, 0x039, 0x038, 0x037, 0x035, 0x034, 0x033, 0x031, 0x030, 0x02f, 0x02e, 0x02d, 0x02b, 0x02a, 0x029, 0x028, 0x027, 0x026, 0x025, 0x024, 0x023, 0x022, 0x021, 0x020, 0x01f, 0x01e, 0x01d, 0x01c, 0x01b, 0x01a, 0x019, 0x018, 0x017, 0x017, 0x016, 0x015, 0x014, 0x014, 0x013, 0x012, 0x011, 0x011, 0x010, 0x00f, 0x00f, 0x00e, 0x00d, 0x00d, 0x00c, 0x00c, 0x00b, 0x00a, 0x00a, 0x009, 0x009, 0x008, 0x008, 0x007, 0x007, 0x007, 0x006, 0x006, 0x005, 0x005, 0x005, 0x004, 0x004, 0x004, 0x003, 0x003, 0x003, 0x002, 0x002, 0x002, 0x002, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000 }; static const ushort exprom[256] = { 0x7fa, 0x7f5, 0x7ef, 0x7ea, 0x7e4, 0x7df, 0x7da, 0x7d4, 0x7cf, 0x7c9, 0x7c4, 0x7bf, 0x7b9, 0x7b4, 0x7ae, 0x7a9, 0x7a4, 0x79f, 0x799, 0x794, 0x78f, 0x78a, 0x784, 0x77f, 0x77a, 0x775, 0x770, 0x76a, 0x765, 0x760, 0x75b, 0x756, 0x751, 0x74c, 0x747, 0x742, 0x73d, 0x738, 0x733, 0x72e, 0x729, 0x724, 0x71f, 0x71a, 0x715, 0x710, 0x70b, 0x706, 0x702, 0x6fd, 0x6f8, 0x6f3, 0x6ee, 0x6e9, 0x6e5, 0x6e0, 0x6db, 0x6d6, 0x6d2, 0x6cd, 0x6c8, 0x6c4, 0x6bf, 0x6ba, 0x6b5, 0x6b1, 0x6ac, 0x6a8, 0x6a3, 0x69e, 0x69a, 0x695, 0x691, 0x68c, 0x688, 0x683, 0x67f, 0x67a, 0x676, 0x671, 0x66d, 0x668, 0x664, 0x65f, 0x65b, 0x657, 0x652, 0x64e, 0x649, 0x645, 0x641, 0x63c, 0x638, 0x634, 0x630, 0x62b, 0x627, 0x623, 0x61e, 0x61a, 0x616, 0x612, 0x60e, 0x609, 0x605, 0x601, 0x5fd, 0x5f9, 0x5f5, 0x5f0, 0x5ec, 0x5e8, 0x5e4, 0x5e0, 0x5dc, 0x5d8, 0x5d4, 0x5d0, 0x5cc, 0x5c8, 0x5c4, 0x5c0, 0x5bc, 0x5b8, 0x5b4, 0x5b0, 0x5ac, 0x5a8, 0x5a4, 0x5a0, 0x59c, 0x599, 0x595, 0x591, 0x58d, 0x589, 0x585, 0x581, 0x57e, 0x57a, 0x576, 0x572, 0x56f, 0x56b, 0x567, 0x563, 0x560, 0x55c, 0x558, 0x554, 0x551, 0x54d, 0x549, 0x546, 0x542, 0x53e, 0x53b, 0x537, 0x534, 0x530, 0x52c, 0x529, 0x525, 0x522, 0x51e, 0x51b, 0x517, 0x514, 0x510, 0x50c, 0x509, 0x506, 0x502, 0x4ff, 0x4fb, 0x4f8, 0x4f4, 0x4f1, 0x4ed, 0x4ea, 0x4e7, 0x4e3, 0x4e0, 0x4dc, 0x4d9, 0x4d6, 0x4d2, 0x4cf, 0x4cc, 0x4c8, 0x4c5, 0x4c2, 0x4be, 0x4bb, 0x4b8, 0x4b5, 0x4b1, 0x4ae, 0x4ab, 0x4a8, 0x4a4, 0x4a1, 0x49e, 0x49b, 0x498, 0x494, 0x491, 0x48e, 0x48b, 0x488, 0x485, 0x482, 0x47e, 0x47b, 0x478, 0x475, 0x472, 0x46f, 0x46c, 0x469, 0x466, 0x463, 0x460, 0x45d, 0x45a, 0x457, 0x454, 0x451, 0x44e, 0x44b, 0x448, 0x445, 0x442, 0x43f, 0x43c, 0x439, 0x436, 0x433, 0x430, 0x42d, 0x42a, 0x428, 0x425, 0x422, 0x41f, 0x41c, 0x419, 0x416, 0x414, 0x411, 0x40e, 0x40b, 0x408, 0x406, 0x403, 0x400 }; static const byte op_mt[16] = { 1, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 20, 24, 24, 30, 30 }; static const byte kslrom[16] = { 0, 32, 40, 45, 48, 51, 53, 55, 56, 58, 59, 60, 61, 62, 63, 64 }; static const byte kslshift[4] = { 8, 1, 2, 0 }; static const byte eg_incstep[4][4] = { { 0, 0, 0, 0 }, { 1, 0, 0, 0 }, { 1, 0, 1, 0 }, { 1, 1, 1, 0 } }; typedef struct _bank_voice bank_voice; typedef struct _bank_key bank_key; typedef struct _bank_channel bank_channel; typedef struct _bank_handle bank_handle; typedef struct _opl3_slot opl3_slot; typedef struct _opl3_channel opl3_channel; typedef struct _opl3_chip opl3_chip; typedef short(*envelope_sinfunc)(ushort phase, ushort envelope); typedef void(*envelope_genfunc)(opl3_slot *slott); typedef struct { byte *buffer; uint size; uint pos; byte status; byte ending; uint wait; ushort trknum; } mid_track; typedef struct { mid_track *track; ushort tracks; uint tpqn; uint uspb; uint ticktime; } mid_handle; typedef struct { byte tremolo; byte vibrato; byte sustaining; byte ksr; byte mult; byte ksl; byte level; byte attack; byte decay; byte sustain; byte release; byte waveform; } bank_operator; typedef struct { bank_operator ops[2]; short detune; short offset; byte feedback; byte am; } bank_pair; typedef struct { bank_pair channels[2]; byte op; byte fixed; byte percnum; char name[32]; } bank_instr; struct _bank_voice { bank_channel *channel; opl3_channel *opl; byte note; byte op; short detune; bank_voice *pair; }; struct _bank_key { byte note; byte velocity; bank_voice *voice; }; struct _bank_channel { bank_handle *bank; bank_key keys[BANK_MAX]; byte notes[128]; byte keyindex; byte active; ushort pbank; char pan; byte volume; short pitch; byte program; bank_instr *instr; byte ch_num; }; struct _bank_handle { bank_channel channel[16]; bank_voice *voices; bank_instr *bdata; ushort voiceindex; ushort v_avail; ushort v_used; byte flags; char velo_func; }; struct _opl3_slot { opl3_channel *channel; opl3_chip *chip; short out; short fbmod; short *mod; short prout; ushort eg_rout; ushort eg_out; byte eg_gen; byte eg_ksl; byte *trem; byte reg_vib; byte reg_type; byte reg_ksr; byte reg_mult; byte reg_ksl; byte reg_tl; byte reg_ar; byte reg_dr; byte reg_sl; byte reg_rr; byte reg_wf; byte key; byte detrigger; byte retrigger; uint pg_reset; uint pg_phase; ushort pg_phase_out; byte slot_num; }; struct _opl3_channel { opl3_slot *slots[2]; opl3_channel *pair; opl3_chip *chip; short *out[4]; int level[2]; byte chtype; ushort f_num; byte block; byte fb; byte con; byte alg; byte ksv; byte ch_num; }; struct _opl3_chip { opl3_channel *channel; opl3_slot *slot; ushort timer; ulong eg_timer; byte eg_timerrem; byte eg_state; byte eg_add; byte nts; byte vibpos; byte vibshift; byte tremolo; byte tremolopos; byte tremoloshift; byte n_voices; uint noise; short zeromod; int mixbuff[4]; int rateratio; int samplecnt; short oldsamples[2]; short samples[2]; }; // OPL3 emulator // Envelope generator short OPL3_EnvelopeCalcExp(uint level) { if (level > 0x1fff) { level = 0x1fff; } return (exprom[level & 0xff] << 1) >> (level >> 8); } short OPL3_EnvelopeCalcSin0(ushort phase, ushort envelope) { ushort out = 0; ushort neg = 0; phase &= 0x3ff; if (phase & 0x200) { neg = 0xffff; } if (phase & 0x100) { out = logsinrom[(phase & 0xff) ^ 0xff]; } else { out = logsinrom[phase & 0xff]; } return OPL3_EnvelopeCalcExp(out + (envelope << 3)) ^ neg; } short OPL3_EnvelopeCalcSin1(ushort phase, ushort envelope) { ushort out = 0; phase &= 0x3ff; if (phase & 0x200) { out = 0x1000; } else if (phase & 0x100) { out = logsinrom[(phase & 0xff) ^ 0xff]; } else { out = logsinrom[phase & 0xff]; } return OPL3_EnvelopeCalcExp(out + (envelope << 3)); } short OPL3_EnvelopeCalcSin2(ushort phase, ushort envelope) { ushort out = 0; phase &= 0x3ff; if (phase & 0x100) { out = logsinrom[(phase & 0xff) ^ 0xff]; } else { out = logsinrom[phase & 0xff]; } return OPL3_EnvelopeCalcExp(out + (envelope << 3)); } short OPL3_EnvelopeCalcSin3(ushort phase, ushort envelope) { ushort out = 0; phase &= 0x3ff; if (phase & 0x100) { out = 0x1000; } else { out = logsinrom[phase & 0xff]; } return OPL3_EnvelopeCalcExp(out + (envelope << 3)); } short OPL3_EnvelopeCalcSin4(ushort phase, ushort envelope) { ushort out = 0; ushort neg = 0; phase &= 0x3ff; if ((phase & 0x300) == 0x100) { neg = 0xffff; } if (phase & 0x200) { out = 0x1000; } else if (phase & 0x80) { out = logsinrom[((phase ^ 0xff) << 1) & 0xff]; } else { out = logsinrom[(phase << 1) & 0xff]; } return OPL3_EnvelopeCalcExp(out + (envelope << 3)) ^ neg; } short OPL3_EnvelopeCalcSin5(ushort phase, ushort envelope) { ushort out = 0; phase &= 0x3ff; if (phase & 0x200) { out = 0x1000; } else if (phase & 0x80) { out = logsinrom[((phase ^ 0xff) << 1) & 0xff]; } else { out = logsinrom[(phase << 1) & 0xff]; } return OPL3_EnvelopeCalcExp(out + (envelope << 3)); } short OPL3_EnvelopeCalcSin6(ushort phase, ushort envelope) { ushort neg = 0; phase &= 0x3ff; if (phase & 0x200) { neg = 0xffff; } return OPL3_EnvelopeCalcExp(envelope << 3) ^ neg; } short OPL3_EnvelopeCalcSin7(ushort phase, ushort envelope) { ushort out = 0; ushort neg = 0; phase &= 0x3ff; if (phase & 0x200) { neg = 0xffff; phase = (phase & 0x1ff) ^ 0x1ff; } out = phase << 3; return OPL3_EnvelopeCalcExp(out + (envelope << 3)) ^ neg; } static const envelope_sinfunc envelope_sin[8] = { OPL3_EnvelopeCalcSin0, OPL3_EnvelopeCalcSin1, OPL3_EnvelopeCalcSin2, OPL3_EnvelopeCalcSin3, OPL3_EnvelopeCalcSin4, OPL3_EnvelopeCalcSin5, OPL3_EnvelopeCalcSin6, OPL3_EnvelopeCalcSin7, }; void OPL3_EnvelopeCalc(opl3_slot *slot) { byte nonzero; byte rate; byte rate_hi; byte rate_lo; byte reg_rate = 0; byte ks; byte eg_shift, shift; ushort eg_rout; short eg_inc; byte eg_off; byte reset = 0; if(slot->retrigger) { slot->eg_rout = 0x1ff; } slot->eg_out = slot->eg_rout + (slot->reg_tl << 2) + (slot->eg_ksl >> kslshift[slot->reg_ksl]) + *slot->trem; if (slot->key && slot->eg_gen == envelope_gen_num_release) { reset = 1; reg_rate = slot->reg_ar; } else { switch (slot->eg_gen) { case envelope_gen_num_attack: reg_rate = slot->reg_ar; break; case envelope_gen_num_decay: reg_rate = slot->reg_dr; break; case envelope_gen_num_sustain: if (!slot->reg_type) { reg_rate = slot->reg_rr; } break; case envelope_gen_num_release: reg_rate = slot->reg_rr; break; } } slot->pg_reset = reset; ks = slot->channel->ksv >> ((slot->reg_ksr ^ 1) << 1); nonzero = (reg_rate != 0); rate = ks + (reg_rate << 2); rate_hi = rate >> 2; rate_lo = rate & 0x03; if (rate_hi & 0x10) { rate_hi = 0x0f; } eg_shift = rate_hi + slot->chip->eg_add; shift = 0; if (nonzero) { if (rate_hi < 12) { if (slot->chip->eg_state) { switch (eg_shift) { case 12: shift = 1; break; case 13: shift = (rate_lo >> 1) & 0x01; break; case 14: shift = rate_lo & 0x01; break; default: break; } } } else { shift = (rate_hi & 0x03) + eg_incstep[rate_lo][slot->chip->timer & 0x03]; if (shift & 0x04) { shift = 0x03; } if (!shift) { shift = slot->chip->eg_state; } } } eg_rout = slot->eg_rout; eg_inc = 0; eg_off = 0; // Instant attack if (reset && rate_hi == 0x0f) { eg_rout = 0x00; } // Envelope off if ((slot->eg_rout & 0x1f8) == 0x1f8) { eg_off = 1; } if (slot->eg_gen != envelope_gen_num_attack && !reset && eg_off) { eg_rout = 0x1ff; } switch (slot->eg_gen) { case envelope_gen_num_attack: if (!(slot->eg_rout)) { slot->eg_gen = envelope_gen_num_decay; } else if (slot->key && shift > 0 && rate_hi != 0x0f) { eg_inc = ~slot->eg_rout >> (4 - shift); } break; case envelope_gen_num_decay: if ((slot->eg_rout >> 4) == slot->reg_sl) { slot->eg_gen = envelope_gen_num_sustain; } else if (!eg_off && !reset && shift > 0) { eg_inc = 1 << (shift - 1); } break; case envelope_gen_num_sustain: case envelope_gen_num_release: if (!eg_off && !reset && shift > 0) { eg_inc = 1 << (shift - 1); } break; } slot->eg_rout = (eg_rout + eg_inc) & 0x1ff; // Key off if (reset) { slot->eg_gen = envelope_gen_num_attack; } if (!(slot->key)) { slot->eg_gen = envelope_gen_num_release; } slot->detrigger = 0; slot->retrigger = 0; } void OPL3_EnvelopeUpdateKSL(opl3_slot *slot) { short ksl = (kslrom[slot->channel->f_num >> 6] << 2) - ((0x08 - slot->channel->block) << 5); if (ksl < 0) { ksl = 0; } slot->eg_ksl = (byte)ksl; } void OPL3_EnvelopeKeyOn(opl3_slot *slot) { slot->key = 0x01; if(slot->detrigger) { slot->eg_gen = envelope_gen_num_release; // slot->eg_rout = 0x1ff; // slot->eg_out = slot->eg_rout = 0x1ff; slot->detrigger = 0; } slot->retrigger = 1; } void OPL3_EnvelopeKeyOff(opl3_slot *slot) { slot->key = 0x00; slot->detrigger = 1; slot->retrigger = 0; } void OPL3_PhaseGenerate(opl3_slot *slot) { opl3_chip *chip; ushort f_num; uint basefreq; ushort phase; chip = slot->chip; f_num = slot->channel->f_num; if (slot->reg_vib) { char range; byte vibpos; range = (f_num >> 7) & 7; vibpos = slot->chip->vibpos; if (!(vibpos & 3)) { range = 0; } else if (vibpos & 1) { range >>= 1; } range >>= slot->chip->vibshift; if (vibpos & 4) { range = -range; } f_num += range; } basefreq = (f_num << slot->channel->block) >> 1; phase = (ushort)(slot->pg_phase >> 9); if (slot->pg_reset) { slot->pg_phase = 0; } slot->pg_phase += (basefreq * op_mt[slot->reg_mult]) >> 1; slot->pg_phase_out = phase; } void OPL3_SlotGenerate(opl3_slot *slot) { slot->out = envelope_sin[slot->reg_wf](slot->pg_phase_out + *slot->mod, slot->eg_out); } void OPL3_SlotCalcFB(opl3_slot *slot) { if (slot->channel->fb != 0x00) { slot->fbmod = (slot->prout + slot->out) >> (0x09 - slot->channel->fb); } else { slot->fbmod = 0; } slot->prout = slot->out; } void OPL3_ProcessSlot(opl3_slot *slot) { OPL3_SlotCalcFB(slot); OPL3_EnvelopeCalc(slot); OPL3_PhaseGenerate(slot); OPL3_SlotGenerate(slot); } short OPL3_ClipSampleOld(int sample) { if (sample > 32767) { sample = 32767; } else if (sample < -32768) { sample = -32768; } return (short)sample; } short OPL3_ClipSample(int sample) { int sign = (sample < 0) ? -1 : 1; sample = (sample < 0) ? -sample : sample; sample *= 5; sample /= 8; sample = sample > 32767 ? 32767 : sample; sample *= sign; return (short)sample; } void OPL3_Generate(opl3_chip *chip, short *buf) { opl3_channel *channel; short **out; int mix[2]; byte ii; short accm; byte shift = 0; buf[0] = OPL3_ClipSample(chip->mixbuff[0]); buf[1] = OPL3_ClipSample(chip->mixbuff[1]); for (ii = 0; ii < (chip->n_voices * 2); ii++) { OPL3_ProcessSlot(&chip->slot[ii]); } mix[0] = mix[1] = 0; for (ii = 0; ii < chip->n_voices; ii++) { channel = &chip->channel[ii]; out = channel->out; accm = *out[0] + *out[1] + *out[2] + *out[3]; mix[0] += (short)((accm * channel->level[0]) >> 16); mix[1] += (short)((accm * channel->level[1]) >> 16); } chip->mixbuff[0] = mix[0]; chip->mixbuff[1] = mix[1]; if ((chip->timer & 0x3f) == 0x3f) { chip->tremolopos = (chip->tremolopos + 1) % 210; } if (chip->tremolopos < 105) { chip->tremolo = chip->tremolopos >> chip->tremoloshift; } else { chip->tremolo = (210 - chip->tremolopos) >> chip->tremoloshift; } if ((chip->timer & 0x3ff) == 0x3ff) { chip->vibpos = (chip->vibpos + 1) & 7; } chip->timer++; chip->eg_add = 0; if (chip->eg_timer) { while (shift < 36 && ((chip->eg_timer >> shift) & 1) == 0) { shift++; } if (shift > 12) { chip->eg_add = 0; } else { chip->eg_add = shift + 1; } } if (chip->eg_timerrem || chip->eg_state) { if (chip->eg_timer == 0xfffffffff) { chip->eg_timer = 0; chip->eg_timerrem = 1; } else { chip->eg_timer++; chip->eg_timerrem = 0; } } chip->eg_state ^= 1; } void OPL3_GenerateResampled(opl3_chip *chip, short *buf) { while (chip->samplecnt >= chip->rateratio) { chip->oldsamples[0] = chip->samples[0]; chip->oldsamples[1] = chip->samples[1]; OPL3_Generate(chip, chip->samples); chip->samplecnt -= chip->rateratio; } buf[0] = (short)((chip->oldsamples[0] * (chip->rateratio - chip->samplecnt) + chip->samples[0] * chip->samplecnt) / chip->rateratio); buf[1] = (short)((chip->oldsamples[1] * (chip->rateratio - chip->samplecnt) + chip->samples[1] * chip->samplecnt) / chip->rateratio); chip->samplecnt += 1 << RSM_FRAC; } // Operator void OPL3_SlotFlags(opl3_slot *slot, byte tremolo, byte vibrato, byte sustaining, byte ksr) { if (tremolo) { slot->trem = &slot->chip->tremolo; } else { slot->trem = (byte*)&slot->chip->zeromod; } slot->reg_vib = vibrato & 0x01; slot->reg_type = sustaining & 0x01; slot->reg_ksr = ksr & 0x01; } void OPL3_SlotMult(opl3_slot *slot, byte mult) { slot->reg_mult = mult & 0x0f; } void OPL3_SlotKSL(opl3_slot *slot, byte ksl) { slot->reg_ksl = ksl & 0x03; OPL3_EnvelopeUpdateKSL(slot); } void OPL3_SlotLevel(opl3_slot *slot, byte level) { slot->reg_tl = level & 0x3f; } void OPL3_SlotADSR(opl3_slot *slot, byte attack, byte decay, byte sustain, byte release) { slot->reg_ar = attack & 0x0f; slot->reg_dr = decay & 0x0f; slot->reg_sl = sustain & 0x0f; if (slot->reg_sl == 0x0f) { slot->reg_sl = 0x1f; } slot->reg_rr = release & 0x0f; if (slot->reg_rr == 0x00) { slot->reg_rr = 0x01; } } void OPL3_SlotWaveform(opl3_slot *slot, byte waveform) { slot->reg_wf = waveform & 0x07; } // Channel void OPL3_ChannelSetupAlg(opl3_channel *channel) { if (channel->alg & 0x08) { return; } if (channel->alg & 0x04) { channel->pair->out[0] = &channel->chip->zeromod; channel->pair->out[1] = &channel->chip->zeromod; channel->pair->out[2] = &channel->chip->zeromod; channel->pair->out[3] = &channel->chip->zeromod; switch (channel->alg & 0x03) { case 0x00: channel->pair->slots[0]->mod = &channel->pair->slots[0]->fbmod; channel->pair->slots[1]->mod = &channel->pair->slots[0]->out; channel->slots[0]->mod = &channel->pair->slots[1]->out; channel->slots[1]->mod = &channel->slots[0]->out; channel->out[0] = &channel->slots[1]->out; channel->out[1] = &channel->chip->zeromod; channel->out[2] = &channel->chip->zeromod; channel->out[3] = &channel->chip->zeromod; break; case 0x01: channel->pair->slots[0]->mod = &channel->pair->slots[0]->fbmod; channel->pair->slots[1]->mod = &channel->pair->slots[0]->out; channel->slots[0]->mod = &channel->chip->zeromod; channel->slots[1]->mod = &channel->slots[0]->out; channel->out[0] = &channel->pair->slots[1]->out; channel->out[1] = &channel->slots[1]->out; channel->out[2] = &channel->chip->zeromod; channel->out[3] = &channel->chip->zeromod; break; case 0x02: channel->pair->slots[0]->mod = &channel->pair->slots[0]->fbmod; channel->pair->slots[1]->mod = &channel->chip->zeromod; channel->slots[0]->mod = &channel->pair->slots[1]->out; channel->slots[1]->mod = &channel->slots[0]->out; channel->out[0] = &channel->pair->slots[0]->out; channel->out[1] = &channel->slots[1]->out; channel->out[2] = &channel->chip->zeromod; channel->out[3] = &channel->chip->zeromod; break; case 0x03: channel->pair->slots[0]->mod = &channel->pair->slots[0]->fbmod; channel->pair->slots[1]->mod = &channel->chip->zeromod; channel->slots[0]->mod = &channel->pair->slots[1]->out; channel->slots[1]->mod = &channel->chip->zeromod; channel->out[0] = &channel->pair->slots[0]->out; channel->out[1] = &channel->slots[0]->out; channel->out[2] = &channel->slots[1]->out; channel->out[3] = &channel->chip->zeromod; break; } } else { switch (channel->alg & 0x01) { case 0x00: channel->slots[0]->mod = &channel->slots[0]->fbmod; channel->slots[1]->mod = &channel->slots[0]->out; channel->out[0] = &channel->slots[1]->out; channel->out[1] = &channel->chip->zeromod; channel->out[2] = &channel->chip->zeromod; channel->out[3] = &channel->chip->zeromod; break; case 0x01: channel->slots[0]->mod = &channel->slots[0]->fbmod; channel->slots[1]->mod = &channel->chip->zeromod; channel->out[0] = &channel->slots[0]->out; channel->out[1] = &channel->slots[1]->out; channel->out[2] = &channel->chip->zeromod; channel->out[3] = &channel->chip->zeromod; break; } } } void OPL3_ChannelUpdateAlg(opl3_channel *channel) { channel->alg = channel->con; if (channel->chtype == ch_4op) { channel->pair->alg = 0x04 | (channel->con << 1) | (channel->pair->con); channel->alg = 0x08; OPL3_ChannelSetupAlg(channel->pair); } else if (channel->chtype == ch_4op2) { channel->alg = 0x04 | (channel->pair->con << 1) | (channel->con); channel->pair->alg = 0x08; OPL3_ChannelSetupAlg(channel); } else { OPL3_ChannelSetupAlg(channel); } } void OPL3_ChannelFreq(opl3_channel *channel, byte block, ushort f_num) { if (channel->chtype == ch_4op2) { return; } channel->f_num = f_num & 0x3ff; channel->block = block & 0x07; channel->ksv = (channel->block << 1) | ((channel->f_num >> (0x09 - channel->chip->nts)) & 0x01); OPL3_EnvelopeUpdateKSL(channel->slots[0]); OPL3_EnvelopeUpdateKSL(channel->slots[1]); if (channel->chtype == ch_4op) { channel->pair->f_num = channel->f_num; channel->pair->block = channel->block; channel->pair->ksv = channel->ksv; OPL3_EnvelopeUpdateKSL(channel->pair->slots[0]); OPL3_EnvelopeUpdateKSL(channel->pair->slots[1]); } } void OPL3_ChannelOutput(opl3_channel *channel, byte output, uint level) { channel->level[output & 1] = level; } void OPL3_Channel4Op(opl3_channel *channel, byte op4) { if (op4) { channel->chtype = ch_4op; channel->pair->chtype = ch_4op2; OPL3_ChannelUpdateAlg(channel); } else { channel->chtype = ch_2op; channel->pair->chtype = ch_2op; OPL3_ChannelUpdateAlg(channel); OPL3_ChannelUpdateAlg(channel->pair); } } void OPL3_ChannelFeedback(opl3_channel *channel, byte feedback) { channel->fb = feedback & 0x07; } void OPL3_ChannelAM(opl3_channel *channel, byte am) { channel->con = am & 0x01; OPL3_ChannelUpdateAlg(channel); } void OPL3_ChannelKeyOn(opl3_channel *channel) { if (channel->chtype == ch_4op) { OPL3_EnvelopeKeyOn(channel->slots[0]); OPL3_EnvelopeKeyOn(channel->slots[1]); OPL3_EnvelopeKeyOn(channel->pair->slots[0]); OPL3_EnvelopeKeyOn(channel->pair->slots[1]); } else if (channel->chtype == ch_2op) { OPL3_EnvelopeKeyOn(channel->slots[0]); OPL3_EnvelopeKeyOn(channel->slots[1]); } } void OPL3_ChannelKeyOff(opl3_channel *channel) { if (channel->chtype == ch_4op) { OPL3_EnvelopeKeyOff(channel->slots[0]); OPL3_EnvelopeKeyOff(channel->slots[1]); OPL3_EnvelopeKeyOff(channel->pair->slots[0]); OPL3_EnvelopeKeyOff(channel->pair->slots[1]); } else if (channel->chtype == ch_2op) { OPL3_EnvelopeKeyOff(channel->slots[0]); OPL3_EnvelopeKeyOff(channel->slots[1]); } } void OPL3_Reset(opl3_chip *chip) { byte slotnum; byte channum; int rateratio = chip->rateratio; byte n_voices = chip->n_voices; opl3_slot *slot = chip->slot; opl3_channel *channel = chip->channel; memset(chip, 0, sizeof(opl3_chip) + (n_voices * (sizeof(opl3_slot) * 2 + sizeof(opl3_channel)))); chip->rateratio = rateratio; chip->n_voices = n_voices; chip->slot = slot; chip->channel = channel; for (slotnum = 0; slotnum < (chip->n_voices * 2); slotnum++) { slot = &chip->slot[slotnum]; slot->chip = chip; slot->mod = &chip->zeromod; slot->eg_rout = 0x1ff; slot->eg_out = 0x1ff; slot->eg_gen = envelope_gen_num_release; slot->trem = (byte*)&chip->zeromod; slot->slot_num = slotnum; } for (channum = 0; channum < chip->n_voices; channum++) { channel = &chip->channel[channum]; channel->slots[0] = &chip->slot[channum * 2]; channel->slots[1] = &chip->slot[channum * 2 + 1]; chip->slot[channum * 2].channel = channel; chip->slot[channum * 2 + 1].channel = channel; channel->pair = &chip->channel[(channum & 1) ? (channum - 1) : (channum + 1)]; channel->chip = chip; channel->out[0] = &chip->zeromod; channel->out[1] = &chip->zeromod; channel->out[2] = &chip->zeromod; channel->out[3] = &chip->zeromod; channel->chtype = ch_2op; channel->level[0] = 0x10000; channel->level[1] = 0x10000; channel->ch_num = channum; OPL3_ChannelSetupAlg(channel); } chip->tremoloshift = 4; chip->vibshift = 1; } void OPL3_Rate(opl3_chip *chip, uint samplerate) { chip->rateratio = (samplerate << RSM_FRAC) / 49716; } void OPL3_ChipFlags(opl3_chip *chip, byte nts, byte vibrato, byte deeptremolo, byte deepvibrato) { chip->nts = nts; chip->tremoloshift = ((deeptremolo ^ 1) << 1) + 2; chip->vibshift = deepvibrato ^ 1; } opl3_chip *OPL3_Alloc(uint samplerate, byte voices) { opl3_chip *chip = malloc(sizeof(opl3_chip) + (voices * (sizeof(opl3_slot) * 2 + sizeof(opl3_channel)))); chip->channel = (opl3_channel*)(((byte*)chip) + sizeof(opl3_chip)); chip->slot = (opl3_slot*)(((byte*)chip->channel) + (voices * sizeof(opl3_channel))); chip->n_voices = voices; OPL3_Rate(chip, samplerate); OPL3_Reset(chip); return chip; } byte OPL3_Playing(opl3_chip *chip) { opl3_slot *slot; for(int z = 0; z < (chip->n_voices * 2); z++) { slot = &chip->slot[z]; if(slot->eg_out <= 0x100) { return 1; } } return 0; } // instrument bank r/w // #ifndef DMX_STDMEM #define DMX_MALLOC(s) mem_alloc(s, MEM_FILE) #define DMX_FREE(p) mem_free(p) // #else // #define DMX_MALLOC(s) malloc(s) // #define DMX_FREE(p) free(p) // #endif // #ifndef DMX_LOG #define DMX_LOG(s, a...) loge(LOG_IO, s, a) // #endif uint bnk_read_mhbank(byte **data, bank_instr **instr, const char *filename, uint minsize, uint maxsize, const char *hdr, uint hdrsize) { int err; FILE *fd = fopen(filename, "rb"); if(fd == NULL) { err = errno; DMX_LOG("Fehler beim Öffnen von Bank-Datei '%s': %s (%d)", filename, strerror(err), err); return 0; } if(fseek(fd, 0L, SEEK_END)) { err = errno; DMX_LOG("Fehler beim Lesen von Bank-Datei '%s': %s (%d)", filename, strerror(err), err); fclose(fd); return 0; } long size = ftell(fd); if(size < 0L) { err = errno; DMX_LOG("Fehler beim Lesen von Bank-Datei '%s': %s (%d)", filename, strerror(err), err); fclose(fd); return 0; } if(fseek(fd, 0L, SEEK_SET)) { err = errno; DMX_LOG("Fehler beim Lesen von Bank-Datei '%s': %s (%d)", filename, strerror(err), err); fclose(fd); return 0; } if(size < (hdrsize+minsize)) { DMX_LOG("Fehler beim Lesen von Bank-Datei '%s': Datei zu klein", filename); fclose(fd); return 0; } if(hdrsize > 0) { byte header[hdrsize]; if(fread(header, 1, hdrsize, fd) != hdrsize) { err = feof(fd); DMX_LOG(err == 0 ? "Fehler beim Lesen von Bank-Datei '%s': E/A-Fehler" : "Fehler beim Lesen von Bank-Datei '%s': Ende der Datei erreicht", filename); fclose(fd); return 0; } if(memcmp(header, hdr, hdrsize) != 0) { DMX_LOG("Fehler beim Lesen von Bank-Datei '%s': Fehlerhafter Dateiheader oder falscher Dateityp", filename); fclose(fd); return 0; } size -= hdrsize; } size = ((maxsize > 0) && (size > maxsize)) ? maxsize : size; *data = DMX_MALLOC(size); if(fread(*data, 1, size, fd) != size) { err = feof(fd); DMX_LOG(err == 0 ? "Fehler beim Lesen von Bank-Datei '%s': E/A-Fehler" : "Fehler beim Lesen von Bank-Datei '%s': Ende der Datei erreicht", filename); fclose(fd); DMX_FREE(*data); return 0; } fclose(fd); *instr = DMX_MALLOC(sizeof(bank_instr)*256); return size; } uint bnk_read_mbank(byte **data, bank_instr **instr, const char *filename, uint minsize, uint maxsize) { return bnk_read_mhbank(data, instr, filename, minsize, maxsize, NULL, 0); } uint bnk_read_hbank(byte **data, bank_instr **instr, const char *filename, uint size, const char *hdr, uint hdrsize) { return bnk_read_mhbank(data, instr, filename, size, size, hdr, hdrsize); } uint bnk_read_sbank(byte **data, bank_instr **instr, const char *filename, uint size) { return bnk_read_mhbank(data, instr, filename, size, size, NULL, 0); } ushort dmx_read_uint16(byte *data) { ushort value = 0; for(int h = 0; h < 2; h++) { value |= ((ushort)data[1-h]); value <<= h < 1 ? 8 : 0; } return value; } ushort dmx_read_uint16be(byte *data) { ushort value = 0; for(int h = 0; h < 2; h++) { value |= ((ushort)data[h]); value <<= h < 1 ? 8 : 0; } return value; } void dmx_read_instr(bank_instr *instr, byte *data, byte 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 = ((short)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 = ((short)dmx_read_uint16(data+14)) + 12; data += 16; } } bank_instr *dmx_read_bank(const char *filename) { byte *data; bank_instr *instr; uint size = bnk_read_hbank(&data, &instr, filename, 175*68, "#OPL_II#", 8); if(size == 0) { return NULL; } byte *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; } DMX_FREE(odata); return instr; } void tmb_read_instr(bank_instr *instr, byte *data, byte 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 : ((char)data[11]); instr->channels[0].detune = 0; } bank_instr *tmb_read_bank(const char *filename) { byte *data; bank_instr *instr; uint size = bnk_read_sbank(&data, &instr, filename, 256*13); if(size == 0) { return NULL; } byte *odata = data; for(int i = 0; i < 256; i++) { tmb_read_instr(&instr[i], data, i >= 128); data += 13; } DMX_FREE(odata); return instr; } void ibk_read_instr(bank_instr *instr, byte *data, byte 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 : ((char)data[13]); instr->channels[0].detune = 0; } bank_instr *ibk_read_bank(const char *filename, byte drum) { byte *data; bank_instr *instr; uint size = bnk_read_hbank(&data, &instr, filename, 128*25, "IBK\x1a", 4); if(size == 0) { return NULL; } byte *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; } DMX_FREE(odata); return instr; } void sb_read_instr(bank_instr *instr, byte *data, byte 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, byte drum) { byte *data; bank_instr *instr; uint size = bnk_read_sbank(&data, &instr, filename, 128*52); if(size == 0) { return NULL; } byte *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; } DMX_FREE(odata); return instr; } void sb3_read_instr(bank_instr *instr, byte *data, byte 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, byte drum) { byte *data; bank_instr *instr; uint size = bnk_read_sbank(&data, &instr, filename, 128*60); if(size == 0) { return NULL; } byte *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; } DMX_FREE(odata); return instr; } void op3_read_instr(bank_instr *instr, byte *data, byte 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) { byte *data; bank_instr *instr; uint size = bnk_read_mhbank(&data, &instr, filename, 16, 256*24+16, "Junglevision Patch File\x1a", 24); if(size == 0) { return NULL; } byte *odata = data; for(int i = 0; i < 256; i++) { instr[i].op = b_op0; instr[i].name[0] = 0; } data += 8; ushort nmelo = dmx_read_uint16(&data[0]); ushort ndrum = dmx_read_uint16(&data[2]); ushort omelo = dmx_read_uint16(&data[4]); ushort odrum = dmx_read_uint16(&data[6]); data += 8; if((((nmelo+ndrum)*24+16) > size) || ((omelo+nmelo) > 128) || ((odrum+ndrum) > 128)) { DMX_LOG("Fehler beim Verarbeiten von Bank-Datei '%s': Ende der Daten erreicht", filename); DMX_FREE(odata); DMX_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; } DMX_FREE(odata); return instr; } void ad_read_instr(bank_instr *instr, byte *data, byte drum, ushort 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) { byte *data; bank_instr *instr; uint size = bnk_read_mbank(&data, &instr, filename, 2, 256*20+2); if(size == 0) { return NULL; } byte *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) { DMX_LOG("Fehler beim Verarbeiten von Bank-Datei '%s': Ende der Daten erreicht", filename); DMX_FREE(odata); DMX_FREE(instr); return NULL; } byte prog = data[0]; if(prog == 0xff) { break; } if(prog >= 128) { continue; } byte bank = data[1]; if((bank != 0) && (bank != 127)) { continue; } ushort offs = dmx_read_uint16(data+2); ushort isize; if(((offs+2) > size) || ((offs+(isize = dmx_read_uint16(odata+offs))) > size) || (isize < 2)) { DMX_LOG("Fehler beim Verarbeiten von Bank-Datei '%s': Ende der Daten erreicht", filename); DMX_FREE(odata); DMX_FREE(instr); return NULL; } ad_read_instr(&instr[prog + ((bank == 127) ? 128 : 0)], odata+(offs+2), bank == 127, isize-2); } DMX_FREE(odata); return instr; } void bk_read_instr(bank_instr *instr, byte *data, byte 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, byte drum) { byte *data; bank_instr *instr; uint size = bnk_read_mbank(&data, &instr, filename, 28, 256*42+28); if(size == 0) { return NULL; } byte *odata = data; if(memcmp(data+2, "ADLIB-", 6) != 0) { DMX_LOG("Fehler beim Lesen von Bank-Datei '%s': Fehlerhafter Dateiheader oder falscher Dateityp", filename); DMX_FREE(odata); DMX_FREE(instr); return NULL; } data += 8; for(int i = 0; i < 256; i++) { instr[i].op = b_op0; instr[i].name[0] = 0; } // ushort nnorm = data[0]; uint ninst = dmx_read_uint16(&data[2]); data += 20; if((ninst*42+28) > size) { DMX_LOG("Fehler beim Verarbeiten von Bank-Datei '%s': Ende der Daten erreicht", filename); DMX_FREE(odata); DMX_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); byte *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; } } DMX_FREE(odata); return instr; } void tim_read_instr(bank_instr *instr, byte *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, byte drum) { byte *data; bank_instr *instr; uint size = bnk_read_mbank(&data, &instr, filename, 6, 256*65+6); if(size == 0) { return NULL; } byte *odata = data; for(int i = 0; i < 256; i++) { instr[i].op = b_op0; instr[i].name[0] = 0; } uint ninst = dmx_read_uint16(&data[2]); data += 6; if((ninst*65+6) > size) { DMX_LOG("Fehler beim Verarbeiten von Bank-Datei '%s': Ende der Daten erreicht", filename); DMX_FREE(odata); DMX_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); byte *ndata = odata+(i*9+6); memcpy(instr[i + (drum ? 128 : 0)].name, ndata, 8); instr[i + (drum ? 128 : 0)].name[8] = 0; } DMX_FREE(odata); return instr; } // SKB! // OO-NNNNN NAME[N] FPPPPPPP AFFFAFFF // DDDDDDDD OOOOOOOO TVSKMMMM KKLLLLLL AAAADDDD SSSSRRRR TVSKMMMM KKLLLLLL AAAADDDD SSSSRRRR -WWW-WWW uint skb_read_instr(bank_instr *instr, byte *data, uint pos, uint size) { if((pos + 1) > size) { return 0; } data += pos; instr->op = (data[0] >> 6) & 0x03; byte 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 = ((short)data[0]) - 128; instr->channels[ch].offset = ((short)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) { byte *data; bank_instr *instr; uint size = bnk_read_mhbank(&data, &instr, filename, 256, 256*56, "SKB!", 4); if(size == 0) { return NULL; } uint pos = 0; for(int i = 0; i < 256; i++) { pos = skb_read_instr(&instr[i], data, pos, size); if(pos == 0) { DMX_LOG("Fehler beim Verarbeiten von Bank-Datei '%s': Ende der Daten erreicht", filename); DMX_FREE(data); DMX_FREE(instr); return NULL; } } DMX_FREE(data); return instr; } bank_instr *bnk_read_bank(const char *filename, byte drum) { int len = 0; int dp = 0; char ch; while(ch = filename[len++]) { if(ch == '.') { dp = len; } } if(dp == 0) { DMX_LOG("Format von Bank-Datei '%s' unbekannt", 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); // } DMX_LOG("Format von Bank-Datei '%s' unbekannt", filename); return NULL; } bank_instr *bnk_read_banks(const char *filename, const char *drumname, byte 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); DMX_FREE(ins2); } else { DMX_FREE(ins1); ins1 = NULL; } } return ins1; } uint skb_write_instr(bank_instr *instr, byte *data, uint pos) { data += pos; byte 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] = (byte)((short)(instr->channels[ch].detune + 128)); data[1] = (byte)((short)(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); } byte skb_write_bank(bank_instr *instr, const char *filename) { int err; FILE *fd = fopen(filename, "wb"); if(fd == NULL) { err = errno; DMX_LOG("Fehler beim Öffnen von Bank-Datei '%s': %s (%d)", filename, strerror(err), err); return 0; } if(fwrite("SKB!", 1, 4, fd) != 4) { DMX_LOG("Fehler beim Schreiben nach Bank-Datei '%s': E/A-Fehler", filename); fclose(fd); return 0; } byte *data = DMX_MALLOC(256*56); uint size = 0; for(int i = 0; i < 256; i++) { size = skb_write_instr(&instr[i], data, size); } if(fwrite(data, 1, size, fd) != size) { DMX_LOG("Fehler beim Schreiben nach Bank-Datei '%s': E/A-Fehler", filename); fclose(fd); DMX_FREE(data); return 0; } fclose(fd); DMX_FREE(data); return 1; } // voice bank void bank_reset(opl3_chip *chip, bank_handle *bank) { ushort voices = chip->n_voices; byte flags = bank->flags; char velo_func = bank->velo_func; bank_instr *instr = bank->bdata; byte *bankdata = (byte*)bank; bankdata += sizeof(bank_handle); memset(bank, 0, sizeof(bank_handle)); bank->voices = (bank_voice*)bankdata; bank->v_avail = voices; bank->flags = flags; bank->velo_func = velo_func; bank->bdata = instr; for(int h = 0; h < 16; h++) { bank_channel *channel = &bank->channel[h]; channel->bank = bank; memset(channel->notes, 0xff, 128); channel->volume = 127; channel->pbank = (h == 9) ? 128 : 0; channel->instr = &bank->bdata[(h == 9) ? 128 : 0]; channel->ch_num = h; } for(int h = 0; h < voices; h++) { bank_voice *voice = &bank->voices[h]; voice->channel = NULL; voice->opl = &chip->channel[h]; voice->note = 0xff; voice->op = b_op2; voice->detune = 0; voice->pair = &bank->voices[h+(((h & 1) == 0) ? 1 : -1)]; } } bank_handle *bank_alloc(opl3_chip *chip, bank_instr *instr, byte keep, byte useunkn, char velofunc) { byte *bankdata = malloc(sizeof(bank_handle) + (sizeof(bank_voice) * chip->n_voices)); bank_handle *bank = (bank_handle*)bankdata; bank->flags = (keep ? BANK_KEEP : 0) | (useunkn ? BANK_UNKN : 0); bank->velo_func = velofunc; bank->bdata = instr; bank_reset(chip, bank); return bank; } byte bank_getnote(bank_channel *ch, byte key, byte id, byte drum, bank_instr *instr) { short note = (short)key; if(instr->fixed) { note = ((short)instr->percnum) + instr->channels[id].offset; } else { note += instr->channels[id].offset; } note = note < 0 ? 0 : note; note = note > 127 ? 127 : note; return (byte)note; } void OPL3_ChannelFreqHz(opl3_channel *channel, uint freq) { uint block = 0; while(opl3_maxfreq[block] < freq) { block++; if(block == 8) { break; } } if(block == 8) { OPL3_ChannelFreq(channel, 7, 1023); return; } double f_num = ((double)freq) / 1000.0 * pow(2.0, (20.0-((double)block))) / 49716.0; OPL3_ChannelFreq(channel, block, (uint)f_num); } uint bank_getfreq(byte key, short pitch, short detune) { double pfrq = pow(2.0, ((((double)pitch) / 8191.0 * BANK_PBRANGE) + (((double)detune) / 100.0)) / 12.0); double freq = ((double)bank_notes[key]) * pfrq; return (uint)freq; } void OPL3_ChannelNote(opl3_channel *channel, byte key, short pitch, short detune) { OPL3_ChannelFreqHz(channel, bank_getfreq(key, pitch, detune)); } uint bank_getlevel(char function, byte velocity, byte volume, char pan) { double lvl = ((function == -128) ? 1.0 : (function ? BANK_VELOFUNC(((double)velocity)/127.0, function < 0 ? (0.1+(1.0-((((double)(-function))-1.0)/126.0))*9.9) : (1.0+((((double)function)-1.0)/126.0)*9.0)) : (((double)velocity)/127.0))) * (((double)volume)/127.0) * (1.0-(0.9*((double)pan)/63.0)); // fprintf(stderr, "%d===%d-->%.2f\n", function, velocity, lvl); lvl *= 65536.0; return (uint)lvl; } void OPL3_ChannelLevelPan(opl3_channel *channel, char function, byte velocity, byte volume, char pan) { OPL3_ChannelOutput(channel, 0, bank_getlevel(function, velocity, volume, pan)); OPL3_ChannelOutput(channel, 1, bank_getlevel(function, velocity, volume, -pan)); } void bank_release_voice(bank_handle *bank, bank_channel *ch, bank_voice *voice) { if(voice->note == 0xff) { return; } OPL3_ChannelKeyOff(voice->opl); voice->note = 0xff; if(voice->op == b_op22) { voice->pair->note = 0xff; OPL3_ChannelKeyOff(voice->pair->opl); bank->v_used -= 2; } else if(voice->op == b_op4) { voice->pair->note = 0xff; bank->v_used -= 2; } else { bank->v_used -= 1; } } bank_voice *bank_release_key(bank_channel *ch, byte note) { if(ch->active == 0) { return NULL; } if(ch->notes[note] == 0xff) { return NULL; } bank_key *key = &ch->keys[ch->notes[note]]; ch->notes[note] = 0xff; ch->active -= 1; if(key->voice) { bank_release_voice(ch->bank, ch, key->voice); } key->velocity = 0; return key->voice; } void bank_init_voice(opl3_channel *channel, bank_instr *instr, byte id) { OPL3_Channel4Op(channel, instr->op == b_op4); for(int o = 0; o < ((instr->op == b_op4) ? 4 : 2); o++) { bank_pair *pair = &instr->channels[(instr->op == b_op4) ? (o >> 1) : id]; bank_operator *op = &pair->ops[o & 1]; opl3_slot *slot = (o >= 2) ? (channel->pair->slots[o & 1]) : (channel->slots[o & 1]); OPL3_SlotFlags(slot, op->tremolo, op->vibrato, op->sustaining, op->ksr); OPL3_SlotMult(slot, op->mult); OPL3_SlotKSL(slot, op->ksl); OPL3_SlotLevel(slot, op->level); OPL3_SlotADSR(slot, op->attack, op->decay, op->sustain, op->release); OPL3_SlotWaveform(slot, op->waveform); if((o & 1) == 1) { opl3_channel *chn = (o >= 2) ? channel->pair : channel; OPL3_ChannelFeedback(chn, pair->feedback); OPL3_ChannelAM(chn, pair->am); } } } bank_voice *bank_get_voice(bank_handle *bank, bank_channel *ch, byte note, byte velocity) { bank_instr *instr = ch->instr; if(ch->pbank == 128) { instr += note; } else if((ch->pbank != 0) && (!(bank->flags & BANK_UNKN))) { return NULL; } if(instr->op == b_op0) { return NULL; } if(bank->v_used == bank->v_avail) { if(bank->flags & BANK_KEEP) { return NULL; } if((instr->op != b_op2) && ((bank->voiceindex & 1) != 0)) { bank->voiceindex += 1; if(bank->voiceindex >= bank->v_avail) { bank->voiceindex = 0; } } bank_release_key(bank->voices[bank->voiceindex].channel, bank->voices[bank->voiceindex].note); } else if((instr->op != b_op2) && ((bank->voiceindex & 1) != 0)) { bank->voiceindex += 1; if(bank->voiceindex >= bank->v_avail) { bank->voiceindex = 0; } } byte vi = bank->voiceindex; while((bank->voices[bank->voiceindex].note != 0xff) || ((instr->op != b_op2) && (bank->voices[bank->voiceindex+1].note != 0xff))) { bank->voiceindex += (instr->op != b_op2) ? 2 : 1; if(bank->voiceindex >= bank->v_avail) { bank->voiceindex = 0; } if(vi == bank->voiceindex) { if(bank->flags & BANK_KEEP) { return NULL; } bank_release_key(bank->voices[bank->voiceindex].channel, bank->voices[bank->voiceindex].note); if((instr->op != b_op2) && (bank->voices[bank->voiceindex+1].note != 0xff)) { bank_release_key(bank->voices[bank->voiceindex+1].channel, bank->voices[bank->voiceindex+1].note); } break; } } bank_voice *voice = &bank->voices[bank->voiceindex]; if((instr->op == b_op2) && (voice->op == b_op4)) { short offset = ((short)bank->voiceindex) + (((bank->voiceindex & 1) == 0) ? 1 : -1); bank_voice *voice2 = &bank->voices[offset]; if(voice2->note == 0xff) { OPL3_ChannelOutput(voice2->opl, 0, 0); OPL3_ChannelOutput(voice2->opl, 1, 0); } } bank->voiceindex += (instr->op != b_op2) ? 2 : 1; if(bank->voiceindex >= bank->v_avail) { bank->voiceindex = 0; } voice->channel = ch; voice->note = note; voice->op = instr->op; voice->detune = instr->channels[0].detune; bank_init_voice(voice->opl, instr, 0); if(voice->op == b_op22) { voice->pair->channel = ch; voice->pair->note = note; voice->pair->op = b_op22; voice->pair->detune = instr->channels[1].detune; bank_init_voice(voice->pair->opl, instr, 1); OPL3_ChannelNote(voice->opl, bank_getnote(ch, note, 0, ch->pbank == 128, instr), ch->pitch, voice->detune); OPL3_ChannelNote(voice->pair->opl, bank_getnote(ch, note, 1, ch->pbank == 128, instr), ch->pitch, voice->pair->detune); OPL3_ChannelLevelPan(voice->opl, bank->velo_func, velocity, ch->volume, ch->pan); OPL3_ChannelLevelPan(voice->pair->opl, bank->velo_func, velocity, ch->volume, ch->pan); OPL3_ChannelKeyOn(voice->opl); OPL3_ChannelKeyOn(voice->pair->opl); bank->v_used += 2; } else if(voice->op == b_op4) { voice->pair->channel = ch; voice->pair->note = note; voice->pair->op = b_op4; OPL3_ChannelNote(voice->opl, bank_getnote(ch, note, 0, ch->pbank == 128, instr), ch->pitch, voice->detune); OPL3_ChannelLevelPan(voice->opl, bank->velo_func, velocity, ch->volume, ch->pan); OPL3_ChannelKeyOn(voice->opl); bank->v_used += 2; } else { OPL3_ChannelNote(voice->opl, bank_getnote(ch, note, 0, ch->pbank == 128, instr), ch->pitch, voice->detune); OPL3_ChannelLevelPan(voice->opl, bank->velo_func, velocity, ch->volume, ch->pan); OPL3_ChannelKeyOn(voice->opl); bank->v_used += 1; } return voice; } bank_voice *bank_press_key(bank_channel *ch, byte note, byte velocity) { if(ch->notes[note] != 0xff) { bank_release_key(ch, note); } if(ch->active == BANK_MAX) { return NULL; } byte ki = ch->keyindex; while(ch->keys[ch->keyindex].velocity != 0) { ch->keyindex += 1; if(ch->keyindex == BANK_MAX) { ch->keyindex = 0; } if(ki == ch->keyindex) { return NULL; } } bank_voice *voice = bank_get_voice(ch->bank, ch, note, velocity); ch->notes[note] = ch->keyindex; ch->active += 1; bank_key *key = &ch->keys[ch->keyindex]; key->note = note; key->velocity = velocity; key->voice = voice; return voice; } void bank_notesoff(bank_channel *ch) { for(int h = 0; (h < BANK_MAX) && (ch->active > 0); h++) { bank_release_key(ch, h); } } void bank_progupdate(bank_channel *ch, opl3_chip *chip) { bank_notesoff(ch); ushort id = ch->program; if(ch->pbank == 128) { id = 128; } else if((ch->pbank != 0) && (!(ch->bank->flags & BANK_UNKN))) { id = 0; } ch->instr = (ch->bank->bdata)+id; } void bank_levelupdate(bank_channel *ch, opl3_chip *chip) { byte done = 0; for(int h = 0; (h < BANK_MAX) && (done < ch->active); h++) { bank_key *key = (ch->keys)+h; if((key->velocity == 0) || (key->voice == NULL)) { continue; } OPL3_ChannelLevelPan(key->voice->opl, ch->bank->velo_func, key->velocity, ch->volume, ch->pan); if(key->voice->op == b_op22) { OPL3_ChannelLevelPan(key->voice->pair->opl, ch->bank->velo_func, key->velocity, ch->volume, ch->pan); } done++; } } void bank_frequpdate(bank_channel *ch, opl3_chip *chip) { byte done = 0; for(int h = 0; (h < BANK_MAX) && (done < ch->active); h++) { bank_key *key = (ch->keys)+h; if((key->velocity == 0) || (key->voice == NULL)) { continue; } OPL3_ChannelNote(key->voice->opl, bank_getnote(ch, key->note, 0, ch->pbank == 128, ch->instr), ch->pitch, key->voice->detune); if(key->voice->op == b_op22) { OPL3_ChannelNote(key->voice->pair->opl, bank_getnote(ch, key->note, 1, ch->pbank == 128, ch->instr), ch->pitch, key->voice->pair->detune); } done++; } } void bank_noteon(bank_handle *bank, opl3_chip *chip, byte channel, byte key, byte velocity) { bank_channel *ch = &bank->channel[channel]; // if((ch->pbank == 128) && ((key < 35) || (key > 81))) { // return; // } bank_press_key(ch, key, velocity); } void bank_noteoff(bank_handle *bank, opl3_chip *chip, byte channel, byte key, byte velocity) { bank_channel *ch = &bank->channel[channel]; // if((ch->pbank == 128) && ((key < 35) || (key > 81))) { // return; // } bank_release_key(ch, key); } void bank_progchange(bank_handle *bank, opl3_chip *chip, byte channel, byte program) { bank_channel *ch = &bank->channel[channel]; ch->program = program; bank_progupdate(ch, chip); } void bank_pitchbend(bank_handle *bank, opl3_chip *chip, byte channel, short pitch) { bank_channel *ch = &bank->channel[channel]; ch->pitch = pitch; bank_frequpdate(ch, chip); } void bank_control(bank_handle *bank, opl3_chip *chip, byte channel, byte control, byte value) { bank_channel *ch = &bank->channel[channel]; switch(control) { case 0x00: // bank MSB // if((channel == 9) && (value == 0)) { // ch->pbank = 128; // } // else { if(channel != 9) { ch->pbank &= 0x007f; ch->pbank |= (((ushort)value) << 7) & 0x3f80; } bank_progupdate(ch, chip); break; case 0x20: // bank LSB // if((channel == 9) && (value == 0)) { // ch->pbank = 128; // } // else { if(channel != 9) { ch->pbank &= 0x3f80; ch->pbank |= ((ushort)value) & 0x007f; } bank_progupdate(ch, chip); break; case 0x07: // volume MSB ch->volume = value; bank_levelupdate(ch, chip); break; case 0x0a: // pan MSB ch->pan = ((char)value) - 64; bank_levelupdate(ch, chip); break; case 0x79: // reset ch->pbank = (channel == 9) ? 128 : 0; ch->volume = 127; ch->pan = 0; bank_progupdate(ch, chip); bank_levelupdate(ch, chip); break; case 0x7b: // all off bank_notesoff(ch); break; } } void bank_alloff(bank_handle *bank) { for(int h = 0; h < 16; h++) { bank_notesoff(&bank->channel[h]); } } // midi logic void snd_logd(const char *fmt, ...); void snd_loge(const char *fmt, ...); // void snd_logx(const char *fmt, ...); void mid_dlog(const char *format, ...) { if(sgt.log_debug) snd_logd(format); } void mid_settempo(mid_handle *mid, uint tempo) { mid->uspb = tempo; mid->ticktime = mid->uspb / mid->tpqn; } uint mid_read_uint32(byte *data) { uint value = 0; for(int h = 0; h < 4; h++) { value |= ((uint)data[h]); value <<= h < 3 ? 8 : 0; } return value; } ushort mid_read_uint16(byte *data) { ushort value = 0; for(int h = 0; h < 2; h++) { value |= ((ushort)data[h]); value <<= h < 1 ? 8 : 0; } return value; } uint midt_read_uint32(mid_track *trk) { uint value = 0; for(int h = 0; h < 4; h++) { if(trk->pos >= trk->size) { break; } value |= ((uint)trk->buffer[trk->pos++]); value <<= h < 3 ? 8 : 0; } return value; } uint midt_read_uint24(mid_track *trk) { uint value = 0; for(int h = 0; h < 3; h++) { if(trk->pos >= trk->size) { break; } value |= ((uint)trk->buffer[trk->pos++]); value <<= h < 2 ? 8 : 0; } return value; } ushort midt_read_uint16(mid_track *trk) { ushort value = 0; for(int h = 0; h < 2; h++) { if(trk->pos >= trk->size) { break; } value |= ((ushort)trk->buffer[trk->pos++]); value <<= h < 1 ? 8 : 0; } return value; } byte midt_read_uint8(mid_track *trk) { byte value = 0; if(trk->pos < trk->size) { value = trk->buffer[trk->pos++]; } return value; } void midt_read_var(mid_track *trk, uint len, byte *chars) { memset(chars, 0, len); for(int h = 0; h < len; h++) { if(trk->pos >= trk->size) { break; } chars[h] = trk->buffer[trk->pos++]; } } uint mid_read_vlen(mid_track *trk) { uint value; byte bt; if(trk->pos >= trk->size) { return 0; } if((value = trk->buffer[trk->pos++]) & 0x80) { value &= 0x7f; do { if(trk->pos >= trk->size) { break; } value = (value << 7) + ((bt = trk->buffer[trk->pos++]) & 0x7f); } while(bt & 0x80); } return value; } uint mid_read(mid_handle *mid, const char *filename) { int err; FILE *fd = fopen(filename, "rb"); if(fd == NULL) { err = errno; loge(LOG_IO, "Fehler beim Öffnen von MIDI-Datei '%s': %s (%d)", filename, strerror(err), err); return 0; } if(fseek(fd, 0L, SEEK_END)) { err = errno; loge(LOG_IO, "Fehler beim Lesen von MIDI-Datei '%s': %s (%d)", filename, strerror(err), err); fclose(fd); return 0; } long size = ftell(fd); if(size < 0L) { err = errno; loge(LOG_IO, "Fehler beim Lesen von MIDI-Datei '%s': %s (%d)", filename, strerror(err), err); fclose(fd); return 0; } if(fseek(fd, 0L, SEEK_SET)) { err = errno; loge(LOG_IO, "Fehler beim Lesen von MIDI-Datei '%s': %s (%d)", filename, strerror(err), err); fclose(fd); return 0; } if(size < 14) { loge(LOG_IO, "Fehler beim Lesen von MIDI-Datei '%s': Datei zu klein", filename); fclose(fd); return 0; } byte header[14]; if(fread(header, 1, 14, fd) != 14) { err = feof(fd); loge(LOG_IO, err == 0 ? "Fehler beim Lesen von MIDI-Datei '%s': E/A-Fehler" : "Fehler beim Lesen von MIDI-Datei '%s': Ende der Datei erreicht", filename); fclose(fd); return 0; } if(memcmp(header, mid_hdr, 4) != 0) { loge(LOG_IO, "Fehler beim Lesen von MIDI-Datei '%s': Fehlerhafter Dateiheader oder falscher Dateityp", filename); fclose(fd); return 0; } if(mid_read_uint32(header+4) != 6) { loge(LOG_IO, "Fehler beim Lesen von MIDI-Datei '%s': Dateiheader mit falscher Länge", filename); fclose(fd); return 0; } byte mtrack; ushort type = mid_read_uint16(header+8); if(type == 0) { mtrack = 0; } else if((type == 1) || (type == 2)) { mtrack = 1; } else { loge(LOG_IO, "Fehler beim Lesen von MIDI-Datei '%s': Fehlerhaftes Spurformat", filename); fclose(fd); return 0; } mid->tracks = mid_read_uint16(header+10); if(mid->tracks == 0) { loge(LOG_IO, "Fehler beim Lesen von MIDI-Datei '%s': Keine Spuren definiert", filename); fclose(fd); return 0; } else if((mtrack ^ 1) && (mid->tracks > 1)) { loge(LOG_IO, "Fehler beim Lesen von MIDI-Datei '%s': Einzelspur-Format mit mehreren Spuren", filename); fclose(fd); return 0; } mid->tpqn = mid_read_uint16(header+12); if((mid->tpqn & 0x8000) > 0) { loge(LOG_IO, "Fehler beim Lesen von MIDI-Datei '%s': SMPTE-Zeitformat nicht unterstützt", filename); fclose(fd); return 0; } if(mid->tpqn == 0) { loge(LOG_IO, "Fehler beim Lesen von MIDI-Datei '%s': Zeitformat teilt durch null", filename); fclose(fd); return 0; } uint esize = 0; for(ushort trk = 0; trk < mid->tracks; trk++) { if(fread(header, 1, 8, fd) != 8) { err = feof(fd); loge(LOG_IO, err == 0 ? "Fehler beim Lesen von MIDI-Datei '%s': E/A-Fehler" : "Fehler beim Lesen von MIDI-Datei '%s': Ende der Datei erreicht", filename); fclose(fd); return 0; } if(memcmp(header, mid_trk, 4) != 0) { loge(LOG_IO, "Fehler beim Lesen von MIDI-Datei '%s': Fehlerhafter Spurheader", filename); fclose(fd); return 0; } uint trks = mid_read_uint32(header+4); if((14 + esize + 8 + trks) > size) { loge(LOG_IO, "Fehler beim Lesen von MIDI-Datei '%s': Spur #%d ausserhalb der Datei", filename, trk+1); fclose(fd); return 0; } if(fseek(fd, trks, SEEK_CUR)) { err = errno; loge(LOG_IO, "Fehler beim Lesen von MIDI-Datei '%s': %s (%d)", filename, strerror(err), err); fclose(fd); return 0; } esize += trks + 8; } if(fseek(fd, 14L, SEEK_SET)) { err = errno; loge(LOG_IO, "Fehler beim Lesen von MIDI-Datei '%s': %s (%d)", filename, strerror(err), err); fclose(fd); return 0; } esize -= (mid->tracks * 8); byte *buf = mem_alloc((sizeof(mid_track) * mid->tracks) + esize, MEM_FILE); mid->track = (mid_track*)buf; buf += (sizeof(mid_track) * mid->tracks); for(ushort trk = 0; trk < mid->tracks; trk++) { memset((mid->track)+trk, 0, sizeof(mid_track)); if(fread(header, 1, 8, fd) != 8) { err = feof(fd); loge(LOG_IO, err == 0 ? "Fehler beim Lesen von MIDI-Datei '%s': E/A-Fehler" : "Fehler beim Lesen von MIDI-Datei '%s': Ende der Datei erreicht", filename); fclose(fd); mem_free(mid->track); return 0; } mid->track[trk].size = mid_read_uint32(header+4); if(fread(buf, 1, mid->track[trk].size, fd) != mid->track[trk].size) { err = feof(fd); loge(LOG_IO, err == 0 ? "Fehler beim Lesen von MIDI-Datei '%s': E/A-Fehler" : "Fehler beim Lesen von MIDI-Datei '%s': Ende der Datei erreicht", filename); fclose(fd); mem_free(mid->track); return 0; } mid->track[trk].buffer = buf; mid->track[trk].pos = 0; mid->track[trk].wait = 0; mid->track[trk].trknum = trk; buf += mid->track[trk].size; } fclose(fd); mid_settempo(mid, MID_DEFTEMPO); return (sizeof(mid_track) * mid->tracks) + esize; } void mid_process_meta(mid_handle *mid, mid_track *trk) { byte meta = midt_read_uint8(trk); uint size = mid_read_vlen(trk); switch(meta) { case midmt_seqnum: if(size == 0) { mid_dlog("MIDI Spur #%d Sequenz-Nummer = %d (eigene)", trk->trknum, trk->trknum); return; } else if(size != 2) { trk->pos += size; snd_loge("MIDI Spur #%d Meta-Event 0x%02x - erwartet %d, hat %d", trk->trknum, meta, 2, size); return; } mid_dlog("MIDI Spur #%d Sequenz-Nummer = %d", trk->trknum, midt_read_uint16(trk)); return; case midmt_text: case midmt_copyright: case midmt_trackname: case midmt_instrname: case midmt_lyric: case midmt_marker: case midmt_cuepoint: { byte dt[size+1]; dt[size] = 0; midt_read_var(trk, size, dt); for(int n = 0; n < size; n++) { if(dt[n] < 0x20) dt[n] = ' '; } mid_dlog("MIDI Spur #%d Text (%d) '%s'", trk->trknum, meta, dt); return; } case midmt_chnprefix: if(size != 1) { trk->pos += size; snd_loge("MIDI Spur #%d Meta-Event 0x%02x - erwartet %d, hat %d", trk->trknum, meta, 1, size); return; } mid_dlog("MIDI Spur #%d Kanal-Praefix = %d", trk->trknum, midt_read_uint8(trk)); return; case midmt_endtrack: trk->pos += size; trk->ending = 1; mid_dlog("MIDI Spur #%d Ende erreicht", trk->trknum); return; case midmt_tempo: if(size != 3) { trk->pos += size; snd_loge("MIDI Spur #%d Meta-Event 0x%02x - erwartet %d, hat %d", trk->trknum, meta, 3, size); return; } mid_settempo(mid, midt_read_uint24(trk)); mid_dlog("MIDI Tempo = %d", 60000000 / mid->uspb); return; case midmt_smpte: if(size != 5) { trk->pos += size; snd_loge("MIDI Spur #%d Meta-Event 0x%02x - erwartet %d, hat %d", trk->trknum, meta, 5, size); return; } trk->pos += 5; mid_dlog("MIDI SMPTE-Event (nicht unterstützt)"); return; case midmt_timesig: { if(size != 4) { trk->pos += size; snd_loge("MIDI Spur #%d Meta-Event 0x%02x - erwartet %d, hat %d", trk->trknum, meta, 4, size); return; } byte n = midt_read_uint8(trk); uint d = 1 << ((uint)midt_read_uint8(trk)); byte c = midt_read_uint8(trk); byte b = midt_read_uint8(trk); mid_dlog("MIDI Takt-Signatur = %d/%d - %d CPC - %d 32PQ", n, d, c, b); return; } case midmt_keysig: { if(size != 2) { trk->pos += size; snd_loge("MIDI Spur #%d Meta-Event 0x%02x - erwartet %d, hat %d", trk->trknum, meta, 2, size); return; } int8_t s = midt_read_uint8(trk); byte m = midt_read_uint8(trk); mid_dlog("MIDI Noten-Signatur = %d - %s", s, (m == 0) ? "MAJOR" : ((m == 1) ? "MINOR" : "- ? -")); return; } case midmt_seqspec: { trk->pos += size; mid_dlog("MIDI Spur #%d Sequenzer-Daten empfangen - %d Bytes", trk->trknum, size); return; } default: trk->pos += size; mid_dlog("MIDI Spur #%d Meta-Event 0x%02x (%d)", trk->trknum, meta, size); return; } } #ifndef MID_NOEVT void mid_process(mid_handle *mid, mid_track *trk, bank_handle *bank, opl3_chip *chip) { #else void mid_process(mid_handle *mid, mid_track *trk) { #endif if(trk->pos >= trk->size) { return; } byte status = trk->buffer[trk->pos++]; if((status & 0x80) == 0) { status = trk->status; trk->pos -= 1; } else { trk->status = status; } if((status & 0xf0) != 0xf0) { byte channel = status & 0x0f; status &= 0xf0; switch(status) { case midev_noteoff: { byte o_key = midt_read_uint8(trk); byte o_velocity = midt_read_uint8(trk); #ifndef MID_NOEVT bank_noteoff(bank, chip, channel, o_key, o_velocity); #endif mid_dlog("MIDI Note-Aus - C%d N%d V%d", channel+1, o_key, o_velocity); break; } case midev_noteon: { byte key = midt_read_uint8(trk); byte velocity = midt_read_uint8(trk); #ifndef MID_NOEVT if(velocity == 0) { bank_noteoff(bank, chip, channel, key, velocity); } else { bank_noteon(bank, chip, channel, key, velocity); } #endif mid_dlog("MIDI Note-An - C%d N%d V%d", channel+1, key, velocity); break; } case midev_aftertouch: { byte pressure = midt_read_uint8(trk); mid_dlog("MIDI Aftertouch - C%d P%d", channel+1, pressure); break; } case midev_control: { byte control = midt_read_uint8(trk); byte value = midt_read_uint8(trk); #ifndef MID_NOEVT bank_control(bank, chip, channel, control, value); #endif mid_dlog("MIDI Controller - C%d N%d V%d", channel+1, control, value); break; } case midev_progchg: { byte program = midt_read_uint8(trk); #ifndef MID_NOEVT bank_progchange(bank, chip, channel, program); #endif mid_dlog("MIDI Programm - C%d P%d", channel+1, program); break; } case midev_chnpressure: { byte cpressure = midt_read_uint8(trk); mid_dlog("MIDI Kanal-Druck - C%d P%d", channel+1, cpressure); break; } case midev_pitchbend: { ushort pb = ((ushort)midt_read_uint8(trk)) | (((ushort)midt_read_uint8(trk)) << 7); short pitch = ((short)pb) - 0x2000; #ifndef MID_NOEVT bank_pitchbend(bank, chip, channel, pitch); #endif mid_dlog("MIDI Pitch-Bend - C%d P%d", channel+1, pitch); break; } } } else { switch(status) { case midev_sysex: { uint slen = mid_read_vlen(trk); trk->pos += slen; mid_dlog("MIDI Sysex (Normal) mit Länge = %d", slen); break; } case midev_songpos: mid_dlog("MIDI Song-Position = %d", ((ushort)midt_read_uint8(trk)) | (((ushort)midt_read_uint8(trk)) << 7)); break; case midev_songsel: mid_dlog("MIDI Song-Auswahl = %d", midt_read_uint8(trk)); break; case midev_tunereq: mid_dlog("MIDI Stimmung angefordert, nichts zu tun?!"); break; case midev_endsysex: { uint elen = mid_read_vlen(trk); trk->pos += elen; mid_dlog("MIDI Sysex (Escape) mit Länge = %d", elen); break; } case midev_clock: case midev_start: case midev_continue: case midev_stop: case midev_actsense: mid_dlog("MIDI Status %d", status); break; case midev_meta: mid_process_meta(mid, trk); break; default: snd_loge("MIDI Status unbekannt: 0x%02x", status); break; } } } #ifndef MID_NOEVT byte mid_tick(mid_handle *mid, bank_handle *bank, opl3_chip *chip) { #else byte mid_tick(mid_handle *mid) { #endif byte end = 1; for(int trk = 0; trk < mid->tracks; trk++) { mid_track *track = (mid->track)+trk; if(track->ending) { continue; } if(track->wait > 0) { track->wait -= 1; if(track->wait > 0) { end = 0; continue; } } while(1) { if(track->pos > 0) { #ifndef MID_NOEVT mid_process(mid, track, bank, chip); #else mid_process(mid, track); #endif if((track->ending ^ 1) && (track->pos >= track->size)) { snd_loge("MIDI Spur #%d endete zu früh", track->trknum); track->ending = 1; } if(track->ending) { break; } } track->wait = mid_read_vlen(track); if(track->wait > 0) { break; } } end &= track->ending; } return end ^ 1; } */ }