📄 lkeymidi.cpp
字号:
else {
inst = midi_channel[channel].patch;
corrected_note = note;
bend = midi_channel[channel].pitch_bend;
sort_out_pitch_bend(&bend, &corrected_note);
}
/* play the note */
midi_alloc_channel = channel;
midi_alloc_note = note;
midi_alloc_vol = vol;
midi_driver->key_on(inst, corrected_note, bend,
sort_out_volume(channel, vol),
midi_channel[channel].pan);
}
/* all_notes_off:
* Turns off all active notes.
*/
static void all_notes_off(int channel)
{
if (midi_driver->raw_midi) {
midi_driver->raw_midi(0xB0+channel);
midi_driver->raw_midi(123);
midi_driver->raw_midi(0);
return;
}
else {
int note, layer;
for (note=0; note<128; note++)
for (layer=0; layer<MIDI_LAYERS; layer++)
if (midi_channel[channel].note[note][layer] >= 0)
midi_note_off(channel, note);
}
}
/* reset_controllers:
* Resets volume, pan, pitch bend, etc, to default positions.
*/
static void reset_controllers(int channel)
{
midi_channel[channel].new_volume = 128;
midi_channel[channel].new_pitch_bend = 0x2000;
switch (channel % 3) {
case 0: midi_channel[channel].pan = ((channel/3) & 1) ? 60 : 68; break;
case 1: midi_channel[channel].pan = 104; break;
case 2: midi_channel[channel].pan = 24; break;
}
if (midi_driver->raw_midi) {
midi_driver->raw_midi(0xB0+channel);
midi_driver->raw_midi(10);
midi_driver->raw_midi(midi_channel[channel].pan);
}
}
/* update_controllers:
* Checks cached controller information and updates active voices.
*/
static void update_controllers()
{
int c, c2;
for (c=0; c<16; c++) {
/* check for volume controller change */
if ((midi_channel[c].volume != midi_channel[c].new_volume) ||
(old_midi_volume != lm_midi_volume)) {
midi_channel[c].volume = midi_channel[c].new_volume;
if (midi_driver->raw_midi) {
midi_driver->raw_midi(0xB0+c);
midi_driver->raw_midi(7);
midi_driver->raw_midi(global_volume_fix(midi_channel[c].volume-1));
}
else {
for (c2=0; c2<MIDI_VOICES; c2++) {
if ((midi_voice[c2].channel == c) &&
(midi_voice[c2].note >= 0)) {
int vol = sort_out_volume(c, midi_voice[c2].volume);
midi_driver->set_volume(c2 + midi_driver->basevoice, vol);
}
}
}
}
/* check for pitch bend change */
if (midi_channel[c].pitch_bend != midi_channel[c].new_pitch_bend) {
midi_channel[c].pitch_bend = midi_channel[c].new_pitch_bend;
if (midi_driver->raw_midi) {
midi_driver->raw_midi(0xE0+c);
midi_driver->raw_midi(midi_channel[c].pitch_bend & 0x7F);
midi_driver->raw_midi(midi_channel[c].pitch_bend >> 7);
}
else {
for (c2=0; c2<MIDI_VOICES; c2++) {
if ((midi_voice[c2].channel == c) &&
(midi_voice[c2].note >= 0)) {
int bend = midi_channel[c].pitch_bend;
int note = midi_voice[c2].note;
sort_out_pitch_bend(&bend, ¬e);
midi_driver->set_pitch(c2 + midi_driver->basevoice, note, bend);
}
}
}
}
}
old_midi_volume = lm_midi_volume;
}
/* process_controller:
* Deals with a MIDI controller message on the specified channel.
*/
static void process_controller(int channel, int ctrl, int data)
{
switch (ctrl) {
case 7: /* main volume */
midi_channel[channel].new_volume = data+1;
break;
case 10: /* pan */
midi_channel[channel].pan = data;
if (midi_driver->raw_midi) {
midi_driver->raw_midi(0xB0+channel);
midi_driver->raw_midi(10);
midi_driver->raw_midi(data);
}
break;
case 121: /* reset all controllers */
reset_controllers(channel);
break;
case 123: /* all notes off */
case 124: /* omni mode off */
case 125: /* omni mode on */
case 126: /* poly mode off */
case 127: /* poly mode on */
all_notes_off(channel);
break;
}
}
/* process_meta_event:
* Processes the next meta-event on the specified track.
*/
static void process_meta_event(unsigned char **pos, long *timer)
{
unsigned char metatype = *((*pos)++);
long length = parse_var_len(pos);
long tempo;
if (midi_meta_callback)
midi_meta_callback(metatype, *pos, length);
if (metatype == 0x2F) { /* end of track */
*pos = NULL;
*timer = LONG_MAX;
return;
}
if (metatype == 0x51) { /* tempo change */
tempo = (*pos)[0] * 0x10000L + (*pos)[1] * 0x100 + (*pos)[2];
midi_new_speed = (tempo/1000) * (TIMERS_PER_SECOND/1000);
midi_new_speed /= midifile->divisions;
}
(*pos) += length;
}
/* process_midi_event:
* Processes the next MIDI event on the specified track.
*/
static void process_midi_event(unsigned char **pos, unsigned char *running_status, long *timer)
{
unsigned char byte1, byte2;
int channel;
unsigned char event;
long l;
event = *((*pos)++);
if (event & 0x80) { /* regular message */
/* no running status for sysex and meta-events! */
if ((event != 0xF0) && (event != 0xF7) && (event != 0xFF))
*running_status = event;
byte1 = (*pos)[0];
byte2 = (*pos)[1];
}
else { /* use running status */
byte1 = event;
byte2 = (*pos)[0];
event = *running_status;
(*pos)--;
}
/* program callback? */
if ((midi_msg_callback) &&
(event != 0xF0) && (event != 0xF7) && (event != 0xFF))
midi_msg_callback(event, byte1, byte2);
channel = event & 0x0F;
switch (event>>4) {
case 0x08: /* note off */
midi_note_off(channel, byte1);
(*pos) += 2;
break;
case 0x09: /* note on */
midi_note_on(channel, byte1, byte2, 1);
(*pos) += 2;
break;
case 0x0A: /* note aftertouch */
(*pos) += 2;
break;
case 0x0B: /* control change */
process_controller(channel, byte1, byte2);
(*pos) += 2;
break;
case 0x0C: /* program change */
midi_channel[channel].patch = byte1;
if (midi_driver->raw_midi)
raw_program_change(channel, byte1);
(*pos) += 1;
break;
case 0x0D: /* channel aftertouch */
(*pos) += 1;
break;
case 0x0E: /* pitch bend */
midi_channel[channel].new_pitch_bend = byte1 + (byte2<<7);
(*pos) += 2;
break;
case 0x0F: /* special event */
switch (event) {
case 0xF0: /* sysex */
case 0xF7:
l = parse_var_len(pos);
if (midi_sysex_callback)
midi_sysex_callback(*pos, l);
(*pos) += l;
break;
case 0xF2: /* song position */
(*pos) += 2;
break;
case 0xF3: /* song select */
(*pos)++;
break;
case 0xFF: /* meta-event */
process_meta_event(pos, timer);
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;
}
}
void lmMidiPause()
{
int c;
if (!lmMidiFlag) return;
if (midifile==NULL||lmMidiFlag==0) return;
lt_remove_int(midi_player);
for (c=0; c<16; c++)
all_notes_off(c);
}
int lmMidiSeek(int target)
{
int old_midi_loop;
MIDI *old_midifile;
MIDI_DRIVER *old_driver;
int old_patch[16];
int old_volume[16];
int old_pan[16];
int old_pitch_bend[16];
int c;
if (midifile==NULL||lmMidiFlag==0) return -1;
/* first stop the player */
lmMidiPause();
/* store current settings */
for (c=0; c<16; c++) {
old_patch[c] = midi_channel[c].patch;
old_volume[c] = midi_channel[c].volume;
old_pan[c] = midi_channel[c].pan;
old_pitch_bend[c] = midi_channel[c].pitch_bend;
}
/* save some variables and give temporary values */
old_driver = midi_driver;
//midi_driver = &midi_none;
old_midi_loop = midi_loop;
midi_loop = 0;
old_midifile = midifile;
/* set flag to tell midi_player not to reinstall itself */
midi_seeking = 1;
/* are we seeking backwards? If so, skip back to the start of the file */
if (target <= midi_pos)
prepare_to_play(midifile);
/* now sit back and let midi_player get to the position */
while ((midi_pos < target) && (midi_pos != -1)) {
int mmpc = midi_pos_counter;
int mmp = midi_pos;
mmpc -= midi_timer_speed;
while (mmpc <= 0) {
mmpc += midi_pos_speed;
mmp++;
}
if (mmp >= target)
break;
midi_player();
}
/* restore previously saved variables */
midi_loop = old_midi_loop;
midi_driver = old_driver;
midi_seeking = 0;
if (midi_pos != -1) {
/* refresh the driver with any changed parameters */
if (midi_driver->raw_midi) {
for (c=0; c<16; c++) {
/* program change (this sets the volume as well) */
if ((midi_channel[c].patch != old_patch[c]) ||
(midi_channel[c].volume != old_volume[c]))
raw_program_change(c, midi_channel[c].patch);
/* pan */
if (midi_channel[c].pan != old_pan[c]) {
midi_driver->raw_midi(0xB0+c);
midi_driver->raw_midi(10);
midi_driver->raw_midi(midi_channel[c].pan);
}
/* pitch bend */
if (midi_channel[c].pitch_bend != old_pitch_bend[c]) {
midi_driver->raw_midi(0xE0+c);
midi_driver->raw_midi(midi_channel[c].pitch_bend & 0x7F);
midi_driver->raw_midi(midi_channel[c].pitch_bend >> 7);
}
}
}
/* if we didn't hit the end of the file, continue playing */
if (!midi_looping) {
lt_install_int(midi_player, 20);
}
return 0;
}
if ((midi_loop) && (!midi_looping)) { /* was file was looped? */
prepare_to_play(old_midifile);
lt_install_int(midi_player, 20);
return 2; /* seek past EOF => file restarted */
}
return 1; /* seek past EOF => file stopped */
}
/* midi_player:
* The core MIDI player: to be used as a timer callback.
*/
static void midi_player()
{ static int c,active;
static long l;
if (!midifile) return;
if (midi_semaphore) {
midi_timer_speed += BPS_TO_TIMER(40);
lt_install_int_ex(midi_player, BPS_TO_TIMER(40));
return;
}
midi_semaphore = TRUE;
_midi_tick++;
do_it_all_again:
for (c=0; c<MIDI_VOICES; c++)
midi_waiting[c].note = -1;
/* deal with each track in turn... */
for (c=0; c<MIDI_TRACKS; c++) {
if (midi_track[c].pos) {
midi_track[c].timer -= midi_timer_speed;
/* while events are waiting, process them */
while (midi_track[c].timer <= 0) {
process_midi_event(&midi_track[c].pos,
&midi_track[c].running_status,
&midi_track[c].timer);
/* read next time offset */
if (midi_track[c].pos) {
l = parse_var_len(&midi_track[c].pos);
l *= midi_speed;
midi_track[c].timer += l;
}
}
}
}
/* update global position value */
midi_pos_counter -= midi_timer_speed;
while (midi_pos_counter <= 0) {
midi_pos_counter += midi_pos_speed;
midi_pos++;
}
/* tempo change? */
if (midi_new_speed > 0) {
for (c=0; c<MIDI_TRACKS; c++) {
if (midi_track[c].pos) {
midi_track[c].timer /= midi_speed;
midi_track[c].timer *= midi_new_speed;
}
}
midi_pos_counter /= midi_speed;
midi_pos_counter *= midi_new_speed;
midi_speed = midi_new_speed;
midi_pos_speed = midi_new_speed * midifile->divisions;
midi_new_speed = -1;
}
/* figure out how long until we need to be called again */
active = 0;
midi_timer_speed = LONG_MAX;
for (c=0; c<MIDI_TRACKS; c++) {
if (midi_track[c].pos) {
active = 1;
if (midi_track[c].timer < midi_timer_speed)
midi_timer_speed = midi_track[c].timer;
}
}
/* end of the music? */
if ((!active) || ((midi_loop_end > 0) && (midi_pos >= midi_loop_end))) {
if ((midi_loop) && (!midi_looping)) {
if (midi_loop_start > 0) {
lt_remove_int(midi_player);
midi_semaphore = FALSE;
midi_looping = TRUE;
if (lmMidiSeek(midi_loop_start) != 0) {
midi_looping = FALSE;
lmStopMidi();
return;
}
midi_looping = FALSE;
midi_semaphore = TRUE;
goto do_it_all_again;
}
else {
for (c=0; c<16; c++)
all_notes_off(c);
prepare_to_play(midifile);
goto do_it_all_again;
}
}
else {
lmStopMidi();
midi_semaphore = FALSE;
return;
}
}
/* reprogram the timer */
if (midi_timer_speed < BPS_TO_TIMER(40))
midi_timer_speed = BPS_TO_TIMER(40);
if (!midi_seeking) lt_install_int_ex(midi_player, midi_timer_speed);
/* controller changes are cached and only processed here, so we can
condense streams of controller data into just a few voice updates */
update_controllers();
/* and deal with any notes that are still waiting to be played */
for (c=0; c<MIDI_VOICES; c++)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -