| 412 | } |
| 413 | |
| 414 | void sendMessageDirect(u8 type, u8 arg1, u8 arg2) |
| 415 | { |
| 416 | u8 msg[] = { type, arg1, arg2 }; |
| 417 | u8 msgType = (type & 0xf0); |
| 418 | u8 len; |
| 419 | |
| 420 | len = (msgType == MID_PROGRAM_CHANGE) ? 2 : 3; |
| 421 | |
| 422 | if (msgType == MID_CONTROL_CHANGE && arg1 == MID_VOLUME_MSB && s_midiDevice && !s_midiDevice->hasGlobalVolumeCtrl()) |
| 423 | { |
| 424 | const s32 channelIndex = type & 0x0f; |
| 425 | s_channelSrcVolume[channelIndex] = arg2; |
| 426 | msg[2] = u8(s_channelSrcVolume[channelIndex] * s_masterVolumeScaled); |
| 427 | } |
| 428 | if (s_midiDevice) { s_midiDevice->message(msg, len); } |
| 429 | |
| 430 | // Record currently playing instruments and the note-on times. |
| 431 | if (msgType == MID_NOTE_OFF || msgType == MID_NOTE_ON) |
| 432 | { |
| 433 | const u8 instr = arg1; |
| 434 | const u8 channel = type & 0x0f; |
| 435 | if (msgType == MID_NOTE_OFF || (msgType == MID_NOTE_ON && arg2 == 0)) // note on + velocity = 0 is the same as note off. |
| 436 | { |
| 437 | s_instrOn[instr].channelMask &= ~(1 << channel); |
| 438 | s_instrOn[instr].time[channel] = 0.0; |
| 439 | } |
| 440 | else // MID_NOTE_ON |
| 441 | { |
| 442 | s_instrOn[instr].channelMask |= (1 << channel); |
| 443 | s_instrOn[instr].time[channel] = s_curNoteTime; |
| 444 | } |
| 445 | } |
| 446 | } |
| 447 | |
| 448 | void detectHangingNotes() |
| 449 | { |
no test coverage detected