📄 midi.h
字号:
p++;
if ((event != 0xF0) && (event != 0xF7) && (event != 0xFF))
running_status = event;
}
else /* use running status */
event = running_status;
switch (event>>4) {
case 0x0C: /* program change! */
patches[*p] = TRUE;
p++;
break;
case 0x09: /* note on, is it a drum? */
if ((event & 0x0F) == 9)
drums[*p] = TRUE;
p += 2;
break;
case 0x08: /* note off */
case 0x0A: /* note aftertouch */
case 0x0B: /* control change */
case 0x0E: /* pitch bend */
p += 2;
break;
case 0x0D: /* channel aftertouch */
p += 1;
break;
case 0x0F: /* special event */
switch (event) {
case 0xF0: /* sysex */
case 0xF7:
l = parse_var_len(&p);
p += l;
break;
case 0xF2: /* song position */
p += 2;
break;
case 0xF3: /* song select */
p++;
break;
case 0xFF: /* meta-event */
p++;
l = parse_var_len(&p);
p += l;
break;
default:
/* the other special events don't have any data bytes,
so we don't need to bother skipping past them */
break;
}
break;
default:
/* something has gone badly wrong if we ever get to here */
break;
}
if (p < end) /* skip time offset */
parse_var_len(&p);
}
}
/* tell the driver to do its stuff */
return midi_driver->load_patches(patches, drums);
}
int MidiPlay(MIDI *midi, int loop)
{
int c;
if (!MidiFlag) return -1;
remove_int(midi_player);
for (c=0; c<16; c++)
all_notes_off(c);
if (midi) {
if (!midi_loaded_patches)
if (load_patches(midi) != 0)
return -1;
midi_loop = loop;
midi_loop_start = -1;
midi_loop_end = -1;
prepare_to_play(midi);
/* arbitrary speed, () will adjust it */
install_int(midi_player, 20);
}
else {
midifile = NULL;
midi_pos = -1;
}
return 0;
}
/* midi_init:
* Sets up the MIDI player ready for use. Returns non-zero on failure.
*/
int midi_init(char driver)
{
int c, c2, c3;
int back = 0;
char buf[16];
midi_loaded_patches = FALSE;
switch (driver)
{ case MIDI_AUTO: midi_driver = &Midi_adlib; break;
case MIDI_ADLIB: midi_driver = &Midi_adlib; break;
case MIDI_DIGI: printf("Haven't supported digi midi\n");
back = 1; break;
default: back = 1;
}
if (back) return FALSE;
if (!midi_driver->detect()) {
sprintf(grp_err,"MIDI detect failed\n");
return FALSE;
}
if (!midi_driver->init(64)) {
sprintf(grp_err,"MIDI init failed\n");
return FALSE;
}
timer_init();
for (c=0; c<16; c++) {
midi_channel[c].volume = 128;
midi_channel[c].pitch_bend = 0x2000;
for (c2=0; c2<128; c2++)
for (c3=0; c3<MIDI_LAYERS; c3++)
midi_channel[c].note[c2][c3] = -1;
}
for (c=0; c<MIDI_VOICES; c++) {
midi_voice[c].note = -1;
midi_voice[c].time = 0;
}
for (c=0; c<128; c++) {
sprintf(buf, "p%d", c+1);
patch_table[c].bank1 = -1;
patch_table[c].bank2 = -1;
patch_table[c].prog = c;
patch_table[c].pitch = 0;
}
return TRUE;
}
void midi_exit()
{
StopMidi();
midi_driver->exit();
}
void prepare_to_play(MIDI *midi)
{
int c;
for (c=0; c<16; c++)
reset_controllers(c);
update_controllers();
midifile = midi;
midi_pos = 0;
midi_pos_counter = 0;
midi_speed = TIMERS_PER_SECOND / 2 / midifile->divisions; /* 120 bpm */
midi_new_speed = -1;
midi_pos_speed = midi_speed * midifile->divisions;
midi_timer_speed = 0;
midi_seeking = 0;
midi_looping = 0;
for (c=0; c<16; c++) {
midi_channel[c].patch = 0;
if (midi_driver->raw_midi)
raw_program_change(c, 0);
}
for (c=0; c<MIDI_TRACKS; c++) {
if (midi->track[c].data) {
midi_track[c].pos = midi->track[c].data;
midi_track[c].timer = parse_var_len(&midi_track[c].pos);
midi_track[c].timer *= midi_speed;
}
else {
midi_track[c].pos = NULL;
midi_track[c].timer = LONG_MAX;
}
midi_track[c].running_status = 0;
}
}
void _set_volume(int digi_volume,int midi_volume)
{ if (midi_volume >= 0) {
if (midi_volume<0) midi_volume=0;
if (midi_volume>255) midi_volume=255;
if ((midi_driver->mixer_volume) &&
(midi_driver->mixer_volume(midi_volume) == 0))
_midi_volume = -1;
else
_midi_volume = midi_volume;
}
if (digi_volume >= 0) {
}
}
typedef struct FM_INSTRUMENT
{
unsigned char characteristic1;
unsigned char characteristic2;
unsigned char level1;
unsigned char level2;
unsigned char attackdecay1;
unsigned char attackdecay2;
unsigned char sustainrelease1;
unsigned char sustainrelease2;
unsigned char wave1;
unsigned char wave2;
unsigned char feedback;
unsigned char freq;
unsigned char key;
unsigned char type;
} FM_INSTRUMENT;
#define FM_HH 1
#define FM_CY 2
#define FM_TT 4
#define FM_SD 8
#define FM_BD 16
/* include the GM patch set (static data) */
#include "midimap.h"
/* is the OPL in percussion mode? */
int fm_drum_mode = FALSE;
/* register offsets for each voice */
int fm_offset[18] = {
0x000, 0x001, 0x002, 0x008, 0x009, 0x00A, 0x010, 0x011, 0x012,
0x100, 0x101, 0x102, 0x108, 0x109, 0x10A, 0x110, 0x111, 0x112
};
/* for converting midi note numbers to FM frequencies */
int fm_freq[13] = {
0x157, 0x16B, 0x181, 0x198, 0x1B0, 0x1CA,
0x1E5, 0x202, 0x220, 0x241, 0x263, 0x287, 0x2AE
};
/* logarithmic relationship between midi and FM volumes */
int fm_vol_table[128] = {
0, 11, 16, 19, 22, 25, 27, 29, 32, 33, 35, 37, 39, 40, 42, 43,
45, 46, 48, 49, 50, 51, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62,
64, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 75, 76, 77,
78, 79, 80, 80, 81, 82, 83, 83, 84, 85, 86, 86, 87, 88, 89, 89,
90, 91, 91, 92, 93, 93, 94, 95, 96, 96, 97, 97, 98, 99, 99, 100,
101, 101, 102, 103, 103, 104, 104, 105, 106, 106, 107, 107, 108,
109, 109, 110, 110, 111, 112, 112, 113, 113, 114, 114, 115, 115,
116, 117, 117, 118, 118, 119, 119, 120, 120, 121, 121, 122, 122,
123, 123, 124, 124, 125, 125, 126, 126, 127
};
/* drum channel tables: BD SD TT CY HH */
int fm_drum_channel[] = { 6, 7, 8, 8, 7 };
int fm_drum_op1[] = { TRUE, FALSE, TRUE, FALSE, TRUE };
int fm_drum_op2[] = { TRUE, TRUE, FALSE, TRUE, FALSE };
/* cached information about the state of the drum channels */
FM_INSTRUMENT *fm_drum_cached_inst1[5];
FM_INSTRUMENT *fm_drum_cached_inst2[5];
int fm_drum_cached_vol1[5];
int fm_drum_cached_vol2[5];
long fm_drum_cached_time[5];
/* various bits of information about the current state of the FM chip */
unsigned char fm_drum_mask;
unsigned char fm_key[18];
unsigned char fm_keyscale[18];
unsigned char fm_feedback[18];
int fm_level[18];
int fm_patch[18];
#define VOICE_OFFSET(x) ((x < 9) ? x : 0x100+x-9)
#define midi_adlib Midi_adlib
int midi_card = MIDI_OPL3;
int _volume_step = 8;
/* fm_reset:
* Resets the FM chip. If enable is set, puts OPL3 cards into OPL3 mode,
* otherwise puts them into OPL2 emulation mode.
*/
void fm_reset(int enable)
{
int i;
for (i=0xF5; i>0; i--)
FMWrite(i, 0);
if (midi_card == MIDI_OPL3) { /* if we have an OPL3... */
lk_fm_delay1 = 1;
lk_fm_delay2 = 2;
FMWrite(0x105, 1); /* enable OPL3 mode */
for (i=0x1F5; i>0x105; i--)
FMWrite(i, 0);
for (i=0x104; i>0x100; i--)
FMWrite(i, 0);
if (!enable)
FMWrite(0x105, 0); /* turn OPL3 mode off again */
}
else {
lk_fm_delay1 = 6;
lk_fm_delay2 = 35;
if (midi_card == MIDI_2XOPL2) /* if we have a second OPL2... */
{
for (i=0x1F5; i>0x100; i--)
FMWrite(i, 0);
FMWrite(0x101, 0x20);
FMWrite(0x1BD, 0xC0);
}
}
for (i=0; i<midi_adlib.voices; i++) {
fm_key[i] = 0;
fm_keyscale[i] = 0;
fm_feedback[i] = 0;
fm_level[i] = 0;
fm_patch[i] = -1;
FMWrite(0x40+fm_offset[i], 63);
FMWrite(0x43+fm_offset[i], 63);
}
for (i=0; i<5; i++) {
fm_drum_cached_inst1[i] = NULL;
fm_drum_cached_inst2[i] = NULL;
fm_drum_cached_vol1[i] = -1;
fm_drum_cached_vol2[i] = -1;
fm_drum_cached_time[i] = 0;
}
FMWrite(0x01, 0x20); /* turn on wave form control */
fm_drum_mode = FALSE;
fm_drum_mask = 0xC0;
FMWrite(0xBD, fm_drum_mask); /* set AM and vibrato to high */
Midi_adlib.xmin = -1;
Midi_adlib.xmax = -1;
}
/* fm_set_drum_mode:
* Switches the OPL synth between normal and percussion modes.
*/
void fm_set_drum_mode(int usedrums)
{
int i;
fm_drum_mode = usedrums;
fm_drum_mask = usedrums ? 0xE0 : 0xC0;
midi_adlib.xmin = usedrums ? 6 : -1;
midi_adlib.xmax = usedrums ? 8 : -1;
for (i=6; i<9; i++)
if (midi_card == MIDI_OPL3)
FMWrite(0xC0+VOICE_OFFSET(i), 0x30);
else
FMWrite(0xC0+VOICE_OFFSET(i), 0);
FMWrite(0xBD, fm_drum_mask);
}
/* fm_set_voice:
* Sets the sound to be used for the specified voice, from a structure
* containing eleven bytes of FM operator data. Note that it doesn't
* actually set the volume: it just stores volume data in the fm_level
* arrays for fm_set_volume() to use.
*/
inline void fm_set_voice(int voice, FM_INSTRUMENT *inst)
{
/* store some info */
fm_keyscale[voice] = inst->level2 & 0xC0;
fm_level[voice] = 63 - (inst->level2 & 63);
fm_feedback[voice] = inst->feedback;
/* write the new data */
FMWrite(0x20+fm_offset[voice], inst->characteristic1);
FMWrite(0x23+fm_offset[voice], inst->characteristic2);
FMWrite(0x60+fm_offset[voice], inst->attackdecay1);
FMWrite(0x63+fm_offset[voice], inst->attackdecay2);
FMWrite(0x80+fm_offset[voice], inst->sustainrelease1);
FMWrite(0x83+fm_offset[voice], inst->sustainrelease2);
FMWrite(0xE0+fm_offset[voice], inst->wave1);
FMWrite(0xE3+fm_offset[voice], inst->wave2);
/* don't set operator1 level for additive synthesis sounds */
if (!(inst->feedback & 1))
FMWrite(0x40+fm_offset[voice], inst->level1);
/* on OPL3, 0xC0 contains pan info, so don't set it until fm_key_on() */
if (midi_card != MIDI_OPL3)
FMWrite(0xC0+VOICE_OFFSET(voice), inst->feedback);
}
/* fm_set_drum_op1:
* Sets the sound for operator #1 of a drum channel.
*/
inline void fm_set_drum_op1(int voice, FM_INSTRUMENT *inst)
{
FMWrite(0x20+fm_offset[voice], inst->characteristic1);
FMWrite(0x60+fm_offset[voice], inst->attackdecay1);
FMWrite(0x80+fm_offset[voice], inst->sustainrelease1);
FMWrite(0xE0+fm_offset[voice], inst->wave1);
}
/* fm_set_drum_op2:
* Sets the sound for operator #2 of a drum channel.
*/
inline void fm_set_drum_op2(int voice, FM_INSTRUMENT *inst)
{
FMWrite(0x23+fm_offset[voice], inst->characteristic2);
FMWrite(0x63+fm_offset[voice], inst->attackdecay2);
FMWrite(0x83+fm_offset[voice], inst->sustainrelease2);
FMWrite(0xE3+fm_offset[voice], inst->wave2);
}
/* fm_set_drum_vol_op1:
* Sets the volume for operator #1 of a drum channel.
*/
inline void fm_set_drum_vol_op1(int voice, int vol)
{
vol = 63 * fm_vol_table[vol] / 128;
vol = MIN((vol * _volume_step)>>2,63);
FMWrite(0x40+fm_offset[voice], (63-vol));
}
/* fm_set_drum_vol_op2:
* Sets the volume for operator #2 of a drum channel.
*/
inline void fm_set_drum_vol_op2(int voice, int vol)
{
vol = 63 * fm_vol_table[vol] / 128;
vol = MIN((vol * _volume_step)>>2,63);
FMWrite(0x43+fm_offset[voice], (63-vol));
}
/* fm_set_drum_pitch:
* Sets the pitch of a drum channel.
*/
inline void fm_set_drum_pitch(int voice, FM_INSTRUMENT *drum)
{
FMWrite(0xA0+VOICE_OFFSET(voice), drum->freq);
FMWrite(0xB0+VOICE_OFFSET(voice), drum->key & 0x1F);
}
/* fm_trigger_drum:
* Triggers a note on a drum channel.
*/
inline void fm_trigger_drum(int inst, int vol)
{
FM_INSTRUMENT *drum = fm_drum+inst;
int d;
if (!fm_drum_mode)
fm_set_drum_mode(TRUE);
if (drum->type == FM_BD)
d = 0;
else if (drum->type == FM_SD)
d = 1;
else if (drum->type == FM_TT)
d = 2;
else if (drum->type == FM_CY)
d = 3;
else
d = 4;
/* don't let drum sounds come too close together */
if (fm_drum_cached_time[d] == _midi_tick)
return;
fm_drum_cached_time[d] = _midi_tick;
fm_drum_mask &= (~drum->type);
FMWrite(0xBD, fm_drum_mask);
vol = vol*3/4;
if (fm_drum_op1[d]) {
if (fm_drum_cached_inst1[d] != drum) {
fm_drum_cached_inst1[d] = drum;
fm_set_drum_op1(fm_drum_channel[d], drum);
}
if (fm_drum_cached_vol1[d] != vol) {
fm_drum_cached_vol1[d] = vol;
fm_set_drum_vol_op1(fm_drum_channel[d], vol);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -