1484 |
pChannel->PortamentoTime = (float) itControlChangeEvent->Param.CC.Value / 127.0f * (float) CONFIG_PORTAMENTO_TIME_MAX + (float) CONFIG_PORTAMENTO_TIME_MIN; |
pChannel->PortamentoTime = (float) itControlChangeEvent->Param.CC.Value / 127.0f * (float) CONFIG_PORTAMENTO_TIME_MAX + (float) CONFIG_PORTAMENTO_TIME_MIN; |
1485 |
break; |
break; |
1486 |
} |
} |
1487 |
case 6: { // data entry (currently only used for RPN and NRPN parameters) |
case 6: { // data entry (MSB) |
1488 |
//dmsg(1,("DATA ENTRY %d\n", itControlChangeEvent->Param.CC.Value)); |
//dmsg(1,("DATA ENTRY MSB %d\n", itControlChangeEvent->Param.CC.Value)); |
1489 |
|
|
1490 |
|
// look-ahead: if next MIDI event is data entry LSB, |
1491 |
|
// then skip this event here for now (to avoid double |
1492 |
|
// handling of what's supposed to be one RPN/NRPN event) |
1493 |
|
if (isNextEventCCNr(itControlChangeEvent, 38)) |
1494 |
|
break; |
1495 |
|
|
1496 |
if (pChannel->GetMidiRpnParameter() >= 0) { // RPN parameter number was sent previously ... |
if (pChannel->GetMidiRpnParameter() >= 0) { // RPN parameter number was sent previously ... |
1497 |
dmsg(4,("Guess it's an RPN ...\n")); |
int ch = itControlChangeEvent->Param.CC.Channel; |
1498 |
if (pChannel->GetMidiRpnParameter() == 2) { // coarse tuning in half tones |
int param = pChannel->GetMidiRpnParameter(); |
1499 |
int transpose = (int) itControlChangeEvent->Param.CC.Value - 64; |
int value = itControlChangeEvent->Param.CC.Value << 7; |
1500 |
// limit to +- two octaves for now |
|
1501 |
transpose = RTMath::Min(transpose, 24); |
// transform event type: CC event -> RPN event |
1502 |
transpose = RTMath::Max(transpose, -24); |
itControlChangeEvent->Type = Event::type_rpn; |
1503 |
pChannel->GlobalTranspose = transpose; |
itControlChangeEvent->Param.RPN.Channel = ch; |
1504 |
// workaround, so we won't have hanging notes |
itControlChangeEvent->Param.RPN.Parameter = param; |
1505 |
pChannel->ReleaseAllVoices(itControlChangeEvent); |
itControlChangeEvent->Param.RPN.Value = value; |
1506 |
} |
|
1507 |
// to prevent other MIDI CC #6 messages to be misenterpreted as RPN value |
// do the actual RPN event processing |
1508 |
|
ProcessHardcodedRpn(pEngineChannel, itControlChangeEvent); |
1509 |
|
|
1510 |
|
// to prevent other data entry messages to be misenterpreted as RPN value |
1511 |
pChannel->ResetMidiRpnParameter(); |
pChannel->ResetMidiRpnParameter(); |
1512 |
} else if (pChannel->GetMidiNrpnParameter() >= 0) { // NRPN parameter number was sent previously ... |
} else if (pChannel->GetMidiNrpnParameter() >= 0) { // NRPN parameter number was sent previously ... |
1513 |
dmsg(4,("Guess it's an NRPN ...\n")); |
int ch = itControlChangeEvent->Param.CC.Channel; |
1514 |
const int NrpnMSB = pChannel->GetMidiNrpnParameter() >> 7; |
int param = pChannel->GetMidiNrpnParameter(); |
1515 |
const int NrpnLSB = pChannel->GetMidiNrpnParameter() & 127; |
int value = itControlChangeEvent->Param.CC.Value << 7; |
1516 |
dmsg(4,("NRPN MSB=%d LSB=%d Data=%d\n", NrpnMSB, NrpnLSB, itControlChangeEvent->Param.CC.Value)); |
|
1517 |
switch (NrpnMSB) { |
// transform event type: CC event -> NRPN event |
1518 |
case 0x1a: { // volume level of note (Roland GS NRPN) |
itControlChangeEvent->Type = Event::type_nrpn; |
1519 |
const uint note = NrpnLSB; |
itControlChangeEvent->Param.RPN.Channel = ch; |
1520 |
const uint vol = itControlChangeEvent->Param.CC.Value; |
itControlChangeEvent->Param.RPN.Parameter = param; |
1521 |
dmsg(4,("Note Volume NRPN received (note=%d,vol=%d).\n", note, vol)); |
itControlChangeEvent->Param.RPN.Value = value; |
1522 |
if (note < 128 && vol < 128) |
|
1523 |
pChannel->pMIDIKeyInfo[note].Volume = VolumeCurve[vol]; |
// do the actual NRPN event processing |
1524 |
break; |
ProcessHardcodedNrpn(pEngineChannel, itControlChangeEvent); |
1525 |
} |
|
1526 |
case 0x1c: { // panpot of note (Roland GS NRPN) |
// to prevent other data entry messages to be misenterpreted as NRPN value |
|
const uint note = NrpnLSB; |
|
|
const uint pan = itControlChangeEvent->Param.CC.Value; |
|
|
dmsg(4,("Note Pan NRPN received (note=%d,pan=%d).\n", note, pan)); |
|
|
if (note < 128 && pan < 128) { |
|
|
pChannel->pMIDIKeyInfo[note].PanLeft = PanCurve[128 - pan]; |
|
|
pChannel->pMIDIKeyInfo[note].PanRight = PanCurve[pan]; |
|
|
} |
|
|
break; |
|
|
} |
|
|
case 0x1d: { // reverb send of note (Roland GS NRPN) |
|
|
const uint note = NrpnLSB; |
|
|
const float reverb = float(itControlChangeEvent->Param.CC.Value) / 127.0f; |
|
|
dmsg(4,("Note Reverb Send NRPN received (note=%d,send=%f).\n", note, reverb)); |
|
|
if (note < 128) |
|
|
pChannel->pMIDIKeyInfo[note].ReverbSend = reverb; |
|
|
break; |
|
|
} |
|
|
case 0x1e: { // chorus send of note (Roland GS NRPN) |
|
|
const uint note = NrpnLSB; |
|
|
const float chorus = float(itControlChangeEvent->Param.CC.Value) / 127.0f; |
|
|
dmsg(4,("Note Chorus Send NRPN received (note=%d,send=%f).\n", note, chorus)); |
|
|
if (note < 128) |
|
|
pChannel->pMIDIKeyInfo[note].ChorusSend = chorus; |
|
|
break; |
|
|
} |
|
|
} |
|
|
// to prevent other MIDI CC #6 messages to be misenterpreted as NRPN value |
|
1527 |
pChannel->ResetMidiNrpnParameter(); |
pChannel->ResetMidiNrpnParameter(); |
1528 |
} |
} |
1529 |
break; |
break; |
1539 |
pChannel->iLastPanRequest = itControlChangeEvent->Param.CC.Value; |
pChannel->iLastPanRequest = itControlChangeEvent->Param.CC.Value; |
1540 |
break; |
break; |
1541 |
} |
} |
1542 |
|
case 38: { // data entry (LSB) |
1543 |
|
//dmsg(1,("DATA ENTRY LSB %d\n", itControlChangeEvent->Param.CC.Value)); |
1544 |
|
int value = 0; |
1545 |
|
|
1546 |
|
// look-back: if previous MIDI event was data entry MSB, |
1547 |
|
// then obtain that value for the MSB value portion |
1548 |
|
if (isPrevEventCCNr(itControlChangeEvent, 6)) |
1549 |
|
value = prevEventOf(itControlChangeEvent)->Param.CC.Value << 7; |
1550 |
|
|
1551 |
|
if (pChannel->GetMidiRpnParameter() >= 0) { // RPN parameter number was sent previously ... |
1552 |
|
int ch = itControlChangeEvent->Param.CC.Channel; |
1553 |
|
int param = pChannel->GetMidiRpnParameter(); |
1554 |
|
value |= itControlChangeEvent->Param.CC.Value; |
1555 |
|
|
1556 |
|
// transform event type: CC event -> RPN event |
1557 |
|
itControlChangeEvent->Type = Event::type_rpn; |
1558 |
|
itControlChangeEvent->Param.RPN.Channel = ch; |
1559 |
|
itControlChangeEvent->Param.RPN.Parameter = param; |
1560 |
|
itControlChangeEvent->Param.RPN.Value = value; |
1561 |
|
|
1562 |
|
// do the actual RPN event processing |
1563 |
|
ProcessHardcodedRpn(pEngineChannel, itControlChangeEvent); |
1564 |
|
|
1565 |
|
// to prevent other data entry messages to be misenterpreted as RPN value |
1566 |
|
pChannel->ResetMidiRpnParameter(); |
1567 |
|
} else if (pChannel->GetMidiNrpnParameter() >= 0) { // NRPN parameter number was sent previously ... |
1568 |
|
int ch = itControlChangeEvent->Param.CC.Channel; |
1569 |
|
int param = pChannel->GetMidiNrpnParameter(); |
1570 |
|
value |= itControlChangeEvent->Param.CC.Value; |
1571 |
|
|
1572 |
|
// transform event type: CC event -> NRPN event |
1573 |
|
itControlChangeEvent->Type = Event::type_nrpn; |
1574 |
|
itControlChangeEvent->Param.RPN.Channel = ch; |
1575 |
|
itControlChangeEvent->Param.RPN.Parameter = param; |
1576 |
|
itControlChangeEvent->Param.RPN.Value = value; |
1577 |
|
|
1578 |
|
// do the actual NRPN event processing |
1579 |
|
ProcessHardcodedNrpn(pEngineChannel, itControlChangeEvent); |
1580 |
|
|
1581 |
|
// to prevent other data entry messages to be misenterpreted as NRPN value |
1582 |
|
pChannel->ResetMidiNrpnParameter(); |
1583 |
|
} |
1584 |
|
break; |
1585 |
|
} |
1586 |
case 64: { // sustain |
case 64: { // sustain |
1587 |
if (itControlChangeEvent->Param.CC.Value >= 64 && !pChannel->SustainPedal) { |
if (itControlChangeEvent->Param.CC.Value >= 64 && !pChannel->SustainPedal) { |
1588 |
dmsg(4,("DAMPER (RIGHT) PEDAL DOWN\n")); |
dmsg(4,("DAMPER (RIGHT) PEDAL DOWN\n")); |
1707 |
break; |
break; |
1708 |
} |
} |
1709 |
} |
} |
1710 |
|
} |
1711 |
|
|
1712 |
|
/** |
1713 |
|
* Process MIDI RPN events with hard coded behavior. |
1714 |
|
* |
1715 |
|
* @param pEngineChannel - engine channel on which the MIDI RPN |
1716 |
|
* event was received |
1717 |
|
* @param itRpnEvent - the actual MIDI RPN event |
1718 |
|
*/ |
1719 |
|
void ProcessHardcodedRpn(EngineChannel* pEngineChannel, |
1720 |
|
Pool<Event>::Iterator& itRpnEvent) |
1721 |
|
{ |
1722 |
|
EngineChannelBase<V, R, I>* pChannel = |
1723 |
|
static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel); |
1724 |
|
|
1725 |
|
if (itRpnEvent->Param.RPN.Parameter == 2) { // coarse tuning in half tones |
1726 |
|
int transpose = (int) itRpnEvent->Param.RPN.ValueMSB() - 64; |
1727 |
|
// limit to +- two octaves for now |
1728 |
|
transpose = RTMath::Min(transpose, 24); |
1729 |
|
transpose = RTMath::Max(transpose, -24); |
1730 |
|
pChannel->GlobalTranspose = transpose; |
1731 |
|
// workaround, so we won't have hanging notes |
1732 |
|
pChannel->ReleaseAllVoices(itRpnEvent); |
1733 |
|
} |
1734 |
|
} |
1735 |
|
|
1736 |
|
/** |
1737 |
|
* Process MIDI NRPN events with hard coded behavior. |
1738 |
|
* |
1739 |
|
* @param pEngineChannel - engine channel on which the MIDI NRPN |
1740 |
|
* event was received |
1741 |
|
* @param itRpnEvent - the actual MIDI NRPN event |
1742 |
|
*/ |
1743 |
|
void ProcessHardcodedNrpn(EngineChannel* pEngineChannel, |
1744 |
|
Pool<Event>::Iterator& itNrpnEvent) |
1745 |
|
{ |
1746 |
|
EngineChannelBase<V, R, I>* pChannel = |
1747 |
|
static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel); |
1748 |
|
|
1749 |
|
switch (itNrpnEvent->Param.NRPN.ParameterMSB()) { |
1750 |
|
case 0x1a: { // volume level of note (Roland GS NRPN) |
1751 |
|
const uint note = itNrpnEvent->Param.NRPN.ParameterLSB(); |
1752 |
|
const uint vol = itNrpnEvent->Param.NRPN.ValueMSB(); |
1753 |
|
dmsg(4,("Note Volume NRPN received (note=%d,vol=%d).\n", note, vol)); |
1754 |
|
if (note < 128 && vol < 128) |
1755 |
|
pChannel->pMIDIKeyInfo[note].Volume = VolumeCurve[vol]; |
1756 |
|
break; |
1757 |
|
} |
1758 |
|
case 0x1c: { // panpot of note (Roland GS NRPN) |
1759 |
|
const uint note = itNrpnEvent->Param.NRPN.ParameterLSB(); |
1760 |
|
const uint pan = itNrpnEvent->Param.NRPN.ValueMSB(); |
1761 |
|
dmsg(4,("Note Pan NRPN received (note=%d,pan=%d).\n", note, pan)); |
1762 |
|
if (note < 128 && pan < 128) { |
1763 |
|
pChannel->pMIDIKeyInfo[note].PanLeft = PanCurve[128 - pan]; |
1764 |
|
pChannel->pMIDIKeyInfo[note].PanRight = PanCurve[pan]; |
1765 |
|
} |
1766 |
|
break; |
1767 |
|
} |
1768 |
|
case 0x1d: { // reverb send of note (Roland GS NRPN) |
1769 |
|
const uint note = itNrpnEvent->Param.NRPN.ParameterLSB(); |
1770 |
|
const float reverb = float(itNrpnEvent->Param.NRPN.Value) / 16383.f; |
1771 |
|
dmsg(4,("Note Reverb Send NRPN received (note=%d,send=%f).\n", note, reverb)); |
1772 |
|
if (note < 128) |
1773 |
|
pChannel->pMIDIKeyInfo[note].ReverbSend = reverb; |
1774 |
|
break; |
1775 |
|
} |
1776 |
|
case 0x1e: { // chorus send of note (Roland GS NRPN) |
1777 |
|
const uint note = itNrpnEvent->Param.NRPN.ParameterLSB(); |
1778 |
|
const float chorus = float(itNrpnEvent->Param.NRPN.Value) / 16383.f; |
1779 |
|
dmsg(4,("Note Chorus Send NRPN received (note=%d,send=%f).\n", note, chorus)); |
1780 |
|
if (note < 128) |
1781 |
|
pChannel->pMIDIKeyInfo[note].ChorusSend = chorus; |
1782 |
|
break; |
1783 |
|
} |
1784 |
|
} |
1785 |
} |
} |
1786 |
|
|
1787 |
virtual D* CreateDiskThread() = 0; |
virtual D* CreateDiskThread() = 0; |