X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fmidi%2B%2B2%2Fchannel.cc;h=f29673722de4109ce8d0f7a33bc26cae176fdbb3;hb=e9752ff93ea44098fd8c02b21a3a787ef1cbf3ab;hp=ed8f4da5bc2b56c7910fd263f5aa7140a4d306ae;hpb=aaabaf5d3c8624f398809bb468e2b121a23abda0;p=ardour.git diff --git a/libs/midi++2/channel.cc b/libs/midi++2/channel.cc index ed8f4da5bc..f29673722d 100644 --- a/libs/midi++2/channel.cc +++ b/libs/midi++2/channel.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 1998-99 Paul Barton-Davis + Copyright (C) 1998-99 Paul Barton-Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -25,13 +25,18 @@ using namespace MIDI; -Channel::Channel (MIDI::byte channelnum, Port &p) +Channel::Channel (MIDI::byte channelnum, Port &p) : _port (p) + , _channel_number (channelnum) + , _rpn_msb (0) + , _rpn_lsb (0) + , _nrpn_msb (0) + , _nrpn_lsb (0) + , _rpn_state (RPNState (0)) + , _nrpn_state (RPNState (0)) { - _channel_number = channelnum; - reset (0, 1, false); -} +} void Channel::connect_signals () @@ -66,7 +71,7 @@ Channel::reset (timestamp_t timestamp, framecnt_t /*nframes*/, bool notes_off) memset (_polypress, 0, sizeof (_polypress)); memset (_controller_msb, 0, sizeof (_controller_msb)); memset (_controller_lsb, 0, sizeof (_controller_lsb)); - + /* zero all controllers XXX not necessarily the right thing */ memset (_controller_val, 0, sizeof (_controller_val)); @@ -75,10 +80,8 @@ Channel::reset (timestamp_t timestamp, framecnt_t /*nframes*/, bool notes_off) _controller_14bit[n] = false; } - _rpn_msb = 0; - _rpn_lsb = 0; - _nrpn_msb = 0; - _nrpn_lsb = 0; + rpn_reset (); + nrpn_reset (); _omni = true; _poly = false; @@ -87,7 +90,27 @@ Channel::reset (timestamp_t timestamp, framecnt_t /*nframes*/, bool notes_off) } void -Channel::process_note_off (Parser & /*parser*/, EventTwoBytes *tb) +Channel::rpn_reset () +{ + _rpn_msb = 0; + _rpn_lsb = 0; + _rpn_val_msb = 0; + _rpn_val_lsb = 0; + _rpn_state = RPNState (0); +} + +void +Channel::nrpn_reset () +{ + _nrpn_msb = 0; + _nrpn_lsb = 0; + _nrpn_val_msb = 0; + _nrpn_val_lsb = 0; + _nrpn_state = RPNState (0); +} + +void +Channel::process_note_off (Parser & /*parser*/, EventTwoBytes *tb) { _last_note_off = tb->note_number; _last_off_velocity = tb->velocity; @@ -98,15 +121,137 @@ Channel::process_note_off (Parser & /*parser*/, EventTwoBytes *tb) } void -Channel::process_note_on (Parser & /*parser*/, EventTwoBytes *tb) +Channel::process_note_on (Parser & /*parser*/, EventTwoBytes *tb) { _last_note_on = tb->note_number; _last_on_velocity = tb->velocity; _notes_on++; } +const Channel::RPNState Channel::RPN_READY_FOR_VALUE = RPNState (HaveLSB|HaveMSB); +const Channel::RPNState Channel::RPN_VALUE_READY = RPNState (HaveLSB|HaveMSB|HaveValue); + +bool +Channel::maybe_process_rpns (Parser& parser, EventTwoBytes *tb) +{ + switch (tb->controller_number) { + case 0x62: + _rpn_state = RPNState (_rpn_state|HaveMSB); + _rpn_lsb = tb->value; + if (_rpn_msb == 0x7f && _rpn_lsb == 0x7f) { + rpn_reset (); + } + return true; + case 0x63: + _rpn_state = RPNState (_rpn_state|HaveLSB); + _rpn_msb = tb->value; + if (_rpn_msb == 0x7f && _rpn_lsb == 0x7f) { + rpn_reset (); + } + return true; + + case 0x64: + _nrpn_state = RPNState (_rpn_state|HaveMSB); + _rpn_lsb = tb->value; + if (_nrpn_msb == 0x7f && _nrpn_lsb == 0x7f) { + nrpn_reset (); + } + return true; + case 0x65: + _nrpn_state = RPNState (_rpn_state|HaveLSB); + _rpn_msb = tb->value; + if (_rpn_msb == 0x7f && _rpn_lsb == 0x7f) { + nrpn_reset (); + } + return true; + } + + if ((_nrpn_state & RPN_READY_FOR_VALUE) == RPN_READY_FOR_VALUE) { + + uint16_t rpn_id = (_rpn_msb << 7)|_rpn_lsb; + + switch (tb->controller_number) { + case 0x60: + /* data increment */ + _nrpn_state = RPNState (_nrpn_state|HaveValue); + parser.channel_nrpn_change[_channel_number] (parser, rpn_id, 1); /* EMIT SIGNAL */ + return true; + case 0x61: + /* data decrement */ + _nrpn_state = RPNState (_nrpn_state|HaveValue); + parser.channel_nrpn_change[_channel_number] (parser, rpn_id, -1); /* EMIT SIGNAL */ + return true; + case 0x06: + /* data entry MSB */ + _nrpn_state = RPNState (_nrpn_state|HaveValue); + _nrpn_val_msb = tb->value; + break; + case 0x26: + /* data entry LSB */ + _nrpn_state = RPNState (_nrpn_state|HaveValue); + _nrpn_val_lsb = tb->value; + } + + if (_nrpn_state == RPN_VALUE_READY) { + + float rpn_val = ((_rpn_val_msb << 7)|_rpn_val_lsb)/16384.0; + + std::pair result = nrpns.insert (std::make_pair (rpn_id, rpn_val)); + + if (!result.second) { + result.first->second = rpn_val; + } + + parser.channel_nrpn[_channel_number] (parser, rpn_id, rpn_val); /* EMIT SIGNAL */ + return true; + } + + } else if ((_rpn_state & RPN_READY_FOR_VALUE) == RPN_READY_FOR_VALUE) { + + uint16_t rpn_id = (_rpn_msb << 7)|_rpn_lsb; + + switch (tb->controller_number) { + case 0x60: + /* data increment */ + _rpn_state = RPNState (_rpn_state|HaveValue); + parser.channel_rpn_change[_channel_number] (parser, rpn_id, 1); /* EMIT SIGNAL */ + return true; + case 0x61: + /* data decrement */ + _rpn_state = RPNState (_rpn_state|HaveValue); + parser.channel_rpn_change[_channel_number] (parser, rpn_id, -1); /* EMIT SIGNAL */ + return true; + case 0x06: + /* data entry MSB */ + _rpn_state = RPNState (_rpn_state|HaveValue); + _rpn_val_msb = tb->value; + break; + case 0x26: + /* data entry LSB */ + _rpn_state = RPNState (_rpn_state|HaveValue); + _rpn_val_lsb = tb->value; + } + + if (_rpn_state == RPN_VALUE_READY) { + + float rpn_val = ((_rpn_val_msb << 7)|_rpn_val_lsb)/16384.0; + + std::pair result = rpns.insert (std::make_pair (rpn_id, rpn_val)); + + if (!result.second) { + result.first->second = rpn_val; + } + + parser.channel_rpn[_channel_number] (parser, rpn_id, rpn_val); /* EMIT SIGNAL */ + return true; + } + } + + return false; +} + void -Channel::process_controller (Parser & /*parser*/, EventTwoBytes *tb) +Channel::process_controller (Parser & parser, EventTwoBytes *tb) { unsigned short cv; @@ -115,10 +260,20 @@ Channel::process_controller (Parser & /*parser*/, EventTwoBytes *tb) all changes *are* atomic. */ - if (tb->controller_number <= 31) { /* unsigned: no test for >= 0 */ + if (maybe_process_rpns (parser, tb)) { + return; + } + + /* Note: if RPN data controllers (0x60, 0x61, 0x6, 0x26) are received + * without a previous RPN parameter ID message, or after the RPN ID + * has been reset, they will be treated like ordinary CC messages. + */ + + + if (tb->controller_number < 32) { /* unsigned: no test for >= 0 */ /* if this controller is already known to use 14 bits, - then treat this value as the MSB, and combine it + then treat this value as the MSB, and combine it with the existing LSB. otherwise, just treat it as a 7 bit value, and set @@ -128,31 +283,32 @@ Channel::process_controller (Parser & /*parser*/, EventTwoBytes *tb) cv = (unsigned short) _controller_val[tb->controller_number]; if (_controller_14bit[tb->controller_number]) { - cv = ((tb->value << 7) | (cv & 0x7f)); + cv = ((tb->value & 0x7f) << 7) | (cv & 0x7f); } else { cv = tb->value; } _controller_val[tb->controller_number] = (controller_value_t)cv; - } else if ((tb->controller_number >= 32 && + } else if ((tb->controller_number >= 32 && tb->controller_number <= 63)) { - - cv = (unsigned short) _controller_val[tb->controller_number]; - /* LSB for CC 0-31 arrived. + int cn = tb->controller_number - 32; + + cv = (unsigned short) _controller_val[cn]; + + /* LSB for CC 0-31 arrived. If this is the first time (i.e. its currently flagged as a 7 bit controller), mark the controller as 14 bit, adjust the existing value - to be the MSB, and OR-in the new LSB value. + to be the MSB, and OR-in the new LSB value. otherwise, OR-in the new low 7bits with the old high 7. */ - int cn = tb->controller_number - 32; - + if (_controller_14bit[cn] == false) { _controller_14bit[cn] = true; cv = (cv << 7) | (tb->value & 0x7f); @@ -160,53 +316,58 @@ Channel::process_controller (Parser & /*parser*/, EventTwoBytes *tb) cv = (cv & 0x3f80) | (tb->value & 0x7f); } - _controller_val[tb->controller_number] = - (controller_value_t) cv; + /* update the 14 bit value */ + _controller_val[cn] = (controller_value_t) cv; + + /* also store the "raw" 7 bit value in the incoming controller + value store + */ + _controller_val[tb->controller_number] = (controller_value_t) tb->value; + } else { /* controller can only take 7 bit values */ - - _controller_val[tb->controller_number] = + + _controller_val[tb->controller_number] = (controller_value_t) tb->value; } /* bank numbers are special, in that they have their own signal */ - if (tb->controller_number == 0) { - _bank_number = (unsigned short) _controller_val[0]; + if (tb->controller_number == 0 || tb->controller_number == 0x20) { + _bank_number = _controller_val[0]; _port.parser()->bank_change (*_port.parser(), _bank_number); _port.parser()->channel_bank_change[_channel_number] (*_port.parser(), _bank_number); } - } void -Channel::process_program_change (Parser & /*parser*/, MIDI::byte val) +Channel::process_program_change (Parser & /*parser*/, MIDI::byte val) { _program_number = val; } void -Channel::process_chanpress (Parser & /*parser*/, MIDI::byte val) +Channel::process_chanpress (Parser & /*parser*/, MIDI::byte val) { _chanpress = val; } void -Channel::process_polypress (Parser & /*parser*/, EventTwoBytes *tb) +Channel::process_polypress (Parser & /*parser*/, EventTwoBytes *tb) { _polypress[tb->note_number] = tb->value; } void -Channel::process_pitchbend (Parser & /*parser*/, pitchbend_t val) +Channel::process_pitchbend (Parser & /*parser*/, pitchbend_t val) { _pitch_bend = val; } void -Channel::process_reset (Parser & /*parser*/) +Channel::process_reset (Parser & /*parser*/) { reset (0, 1); } @@ -266,3 +427,35 @@ Channel::channel_msg (MIDI::byte id, MIDI::byte val1, MIDI::byte val2, timestamp return _port.midimsg (msg, len, timestamp); } + +float +Channel::rpn_value (uint16_t rpn) const +{ + return rpn_value_absolute (rpn) / 16384.0f; +} + +float +Channel::rpn_value_absolute (uint16_t rpn) const +{ + RPNList::const_iterator r = rpns.find (rpn); + if (r == rpns.end()) { + return 0.0; + } + return r->second; +} + +float +Channel::nrpn_value (uint16_t nrpn) const +{ + return nrpn_value_absolute (nrpn) / 16384.0f; +} + +float +Channel::nrpn_value_absolute (uint16_t nrpn) const +{ + RPNList::const_iterator r = nrpns.find (nrpn); + if (r == nrpns.end()) { + return 0.0; + } + return r->second; +}