Skip to content

Commit 7c0a1a6

Browse files
committed
midi: allow to enable velocity 0 <=> note off
1 parent a796add commit 7c0a1a6

3 files changed

Lines changed: 70 additions & 22 deletions

File tree

3rdparty/libremidi

src/ossia/protocols/midi/midi_protocol.cpp

Lines changed: 59 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,24 @@ static constexpr auto midi_api(libremidi::API api)
1515
return (api == libremidi::API::UNSPECIFIED) ? libremidi::midi1::default_api() : api;
1616
}
1717
midi_protocol::midi_protocol(
18-
ossia::net::network_context_ptr ctx, std::string device_name,
18+
ossia::net::network_context_ptr ctx, midi_protocol_configuration config,
1919
libremidi::input_configuration& conf, libremidi::input_api_configuration api)
2020
: protocol_base{flags{}}
2121
, m_context{ctx}
22+
, m_config{std::move(config)}
2223
{
23-
conf.on_message = [this](const libremidi::message& m) { midi_callback(m); };
24+
conf.on_message = [this](libremidi::message&& m) { midi_callback(std::move(m)); };
2425

2526
conf.ignore_timing = false;
2627
m_input = std::make_unique<libremidi::midi_in>(conf, api);
2728
}
2829

2930
midi_protocol::midi_protocol(
30-
ossia::net::network_context_ptr ctx, std::string device_name,
31+
ossia::net::network_context_ptr ctx, midi_protocol_configuration config,
3132
libremidi::output_configuration& conf, libremidi::output_api_configuration api)
3233
: protocol_base{flags{}}
3334
, m_context{ctx}
35+
, m_config{std::move(config)}
3436
{
3537
m_output = std::make_unique<libremidi::midi_out>(conf, api);
3638
}
@@ -162,16 +164,34 @@ bool midi_protocol::pull(parameter_base& address)
162164

163165
case address_info::Type::NoteOff_N: {
164166
const midi_channel& chan = m_channels[adrinfo.channel - 1];
165-
int32_t val{chan.note_off_N[adrinfo.note]};
166-
address.set_value(val);
167+
if(m_config.velocity_zero_is_note_off)
168+
{
169+
int32_t val{chan.note_on_N[adrinfo.note]};
170+
address.set_value(0);
171+
}
172+
else
173+
{
174+
int32_t val{chan.note_off_N[adrinfo.note]};
175+
address.set_value(val);
176+
}
167177
return true;
168178
}
169179

170180
case address_info::Type::NoteOff: {
171181
const midi_channel& chan = m_channels[adrinfo.channel - 1];
172-
std::vector<ossia::value> val{
173-
int32_t{chan.note_off.first}, int32_t{chan.note_off.second}};
174-
address.set_value(ossia::value{std::move(val)});
182+
183+
if(m_config.velocity_zero_is_note_off)
184+
{
185+
std::vector<ossia::value> val{
186+
int32_t{chan.note_on.first}, int32_t{0}};
187+
address.set_value(ossia::value{std::move(val)});
188+
}
189+
else
190+
{
191+
std::vector<ossia::value> val{
192+
int32_t{chan.note_off.first}, int32_t{chan.note_off.second}};
193+
address.set_value(ossia::value{std::move(val)});
194+
}
175195
return true;
176196
}
177197

@@ -233,15 +253,23 @@ bool midi_protocol::push(const parameter_base& address, const ossia::value& v)
233253
}
234254

235255
case address_info::Type::NoteOff_N: {
236-
m_output->send_message(libremidi::channel_events::note_off(
237-
adrinfo.channel, adrinfo.note, to_int(v)));
256+
if(m_config.velocity_zero_is_note_off)
257+
m_output->send_message(libremidi::channel_events::note_on(
258+
adrinfo.channel, adrinfo.note, 0));
259+
else
260+
m_output->send_message(libremidi::channel_events::note_off(
261+
adrinfo.channel, adrinfo.note, to_int(v)));
238262
return true;
239263
}
240264

241265
case address_info::Type::NoteOff: {
242266
auto& val = v.get<std::vector<ossia::value>>();
243-
m_output->send_message(libremidi::channel_events::note_off(
244-
adrinfo.channel, to_int(val[0]), to_int(val[1])));
267+
if(m_config.velocity_zero_is_note_off)
268+
m_output->send_message(libremidi::channel_events::note_on(
269+
adrinfo.channel, to_int(val[0]), 0));
270+
else
271+
m_output->send_message(libremidi::channel_events::note_off(
272+
adrinfo.channel, to_int(val[0]), to_int(val[1])));
245273
return true;
246274
}
247275

@@ -328,7 +356,10 @@ bool midi_protocol::observe(parameter_base& address, bool enable)
328356
}
329357
case address_info::Type::NoteOff: {
330358
midi_channel& chan = m_channels[adrinfo.channel - 1];
331-
chan.callback_note_off = enable;
359+
if(m_config.velocity_zero_is_note_off)
360+
chan.callback_note_on = enable;
361+
else
362+
chan.callback_note_off = enable;
332363
return true;
333364
}
334365
case address_info::Type::CC: {
@@ -348,7 +379,10 @@ bool midi_protocol::observe(parameter_base& address, bool enable)
348379
}
349380
case address_info::Type::NoteOff_N: {
350381
midi_channel& chan = m_channels[adrinfo.channel - 1];
351-
chan.callback_note_off_N[adrinfo.note] = enable;
382+
if(m_config.velocity_zero_is_note_off)
383+
chan.callback_note_on_N[adrinfo.note] = enable;
384+
else
385+
chan.callback_note_off_N[adrinfo.note] = enable;
352386
return true;
353387
}
354388
case address_info::Type::CC_N: {
@@ -546,7 +580,7 @@ void midi_protocol::value_callback(
546580
m_dev->on_message(param);
547581
}
548582

549-
void midi_protocol::midi_callback(const libremidi::message& mess)
583+
void midi_protocol::midi_callback(libremidi::message&& mess)
550584
{
551585
if(m_logger.inbound_logger)
552586
{
@@ -559,6 +593,16 @@ void midi_protocol::midi_callback(const libremidi::message& mess)
559593
m_logger.inbound_logger->info("MIDI in: {0}", mess.bytes[0]);
560594
}
561595

596+
if(this->m_config.velocity_zero_is_note_off) {
597+
if(mess.get_message_type() == libremidi::message_type::NOTE_ON) {
598+
const auto status = mess.bytes[0];
599+
const auto note = mess.bytes[1];
600+
const auto vel = mess.bytes[2];
601+
if(vel == 0)
602+
mess.bytes[0] = (status & 0x0F) | 0x80;
603+
}
604+
}
605+
562606
if(m_learning)
563607
{
564608
on_learn(mess);

src/ossia/protocols/midi/midi_protocol.hpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,20 +64,23 @@ struct OSSIA_EXPORT midi_info
6464
bool is_virtual{};
6565
};
6666

67+
struct midi_protocol_configuration
68+
{
69+
std::string device_name;
70+
bool velocity_zero_is_note_off{};
71+
};
72+
6773
class OSSIA_EXPORT midi_protocol final
6874
: public ossia::net::protocol_base
6975
, public Nano::Observer
7076
{
7177
public:
7278
explicit midi_protocol(
73-
ossia::net::network_context_ptr, std::string device_name,
79+
ossia::net::network_context_ptr, midi_protocol_configuration,
7480
libremidi::input_configuration&, libremidi::input_api_configuration midi_api);
7581
explicit midi_protocol(
76-
ossia::net::network_context_ptr, std::string device_name,
82+
ossia::net::network_context_ptr, midi_protocol_configuration,
7783
libremidi::output_configuration&, libremidi::output_api_configuration midi_api);
78-
explicit midi_protocol(
79-
ossia::net::network_context_ptr, midi_info,
80-
libremidi::API api = libremidi::API::UNSPECIFIED);
8184
~midi_protocol();
8285

8386
bool set_info(midi_info);
@@ -109,6 +112,7 @@ class OSSIA_EXPORT midi_protocol final
109112

110113
std::array<midi_channel, 16> m_channels;
111114

115+
midi_protocol_configuration m_config{};
112116
midi_info m_info{};
113117
midi_device* m_dev{};
114118
bool m_registers{};
@@ -132,7 +136,7 @@ class OSSIA_EXPORT midi_protocol final
132136
void value_callback(
133137
bool observed, ossia::net::parameter_base& param, const ossia::value& val);
134138

135-
void midi_callback(const libremidi::message&);
139+
void midi_callback(libremidi::message&&);
136140
void on_learn(const libremidi::message& m);
137141

138142
libremidi::midi1_to_midi2 to_midi2;

0 commit comments

Comments
 (0)