aboutsummaryrefslogtreecommitdiffhomepage
path: root/backends
diff options
context:
space:
mode:
Diffstat (limited to 'backends')
-rw-r--r--backends/jack.c72
-rw-r--r--backends/jack.h10
-rw-r--r--backends/jack.md7
-rw-r--r--backends/winmidi.c2
4 files changed, 87 insertions, 4 deletions
diff --git a/backends/jack.c b/backends/jack.c
index a3caf73..176144f 100644
--- a/backends/jack.c
+++ b/backends/jack.c
@@ -101,6 +101,68 @@ static void mmjack_process_midiout(void* buffer, size_t sample_offset, uint8_t t
}
}
+//this state machine was copied more-or-less verbatim from the alsa midi implementation - fixes there will need to be integrated
+static void mmjack_handle_epn(mmjack_port* port, uint8_t chan, uint16_t control, uint16_t value){
+ mmjack_channel_ident ident = {
+ .label = 0
+ };
+
+ //switching between nrpn and rpn clears all valid bits
+ if(((port->epn_status[chan] & EPN_NRPN) && (control == 101 || control == 100))
+ || (!(port->epn_status[chan] & EPN_NRPN) && (control == 99 || control == 98))){
+ port->epn_status[chan] &= ~(EPN_NRPN | EPN_PARAMETER_LO | EPN_PARAMETER_HI);
+ }
+
+ //setting an address always invalidates the value valid bits
+ if(control >= 98 && control <= 101){
+ port->epn_status[chan] &= ~EPN_VALUE_HI;
+ }
+
+ //parameter hi
+ if(control == 101 || control == 99){
+ port->epn_control[chan] &= 0x7F;
+ port->epn_control[chan] |= value << 7;
+ port->epn_status[chan] |= EPN_PARAMETER_HI | ((control == 99) ? EPN_NRPN : 0);
+ if(control == 101 && value == 127){
+ port->epn_status[chan] &= ~EPN_PARAMETER_HI;
+ }
+ }
+
+ //parameter lo
+ if(control == 100 || control == 98){
+ port->epn_control[chan] &= ~0x7F;
+ port->epn_control[chan] |= value & 0x7F;
+ port->epn_status[chan] |= EPN_PARAMETER_LO | ((control == 98) ? EPN_NRPN : 0);
+ if(control == 100 && value == 127){
+ port->epn_status[chan] &= ~EPN_PARAMETER_LO;
+ }
+ }
+
+ //value hi, clears low, mark as update candidate
+ if(control == 6
+ //check if parameter is set before accepting value update
+ && ((port->epn_status[chan] & (EPN_PARAMETER_HI | EPN_PARAMETER_LO)) == (EPN_PARAMETER_HI | EPN_PARAMETER_LO))){
+ port->epn_value[chan] = value << 7;
+ port->epn_status[chan] |= EPN_VALUE_HI;
+ }
+
+ //value lo, flush the value
+ if(control == 38
+ && port->epn_status[chan] & EPN_VALUE_HI){
+ port->epn_value[chan] &= ~0x7F;
+ port->epn_value[chan] |= value & 0x7F;
+ port->epn_status[chan] &= ~EPN_VALUE_HI;
+
+ //find the updated channel
+ ident.fields.sub_type = port->epn_status[chan] & EPN_NRPN ? midi_nrpn : midi_rpn;
+ ident.fields.sub_channel = chan;
+ ident.fields.sub_control = port->epn_control[chan];
+
+ //ident.fields.port set on output in mmjack_handle_midi
+ mmjack_midiqueue_append(port, ident, port->epn_value[chan]);
+ }
+}
+
static int mmjack_process_midi(instance* inst, mmjack_port* port, size_t nframes, size_t* mark){
mmjack_instance_data* data = (mmjack_instance_data*) inst->impl;
void* buffer = jack_port_get_buffer(port->port, nframes);
@@ -113,7 +175,6 @@ static int mmjack_process_midi(instance* inst, mmjack_port* port, size_t nframes
if(port->input){
if(event_count){
DBGPF("Reading %u MIDI events from port %s", event_count, port->name);
- //TODO (n)rpn RX
for(u = 0; u < event_count; u++){
ident.label = 0;
//read midi data from stream
@@ -135,6 +196,15 @@ static int mmjack_process_midi(instance* inst, mmjack_port* port, size_t nframes
ident.fields.sub_control = 0;
value = event.buffer[1];
}
+
+ //forward the EPN CCs to the EPN state machine
+ if(ident.fields.sub_type == midi_cc
+ && ((ident.fields.sub_control <= 101 && ident.fields.sub_control >= 98)
+ || ident.fields.sub_control == 6
+ || ident.fields.sub_control == 38)){
+ mmjack_handle_epn(port, ident.fields.sub_channel, ident.fields.sub_control, value);
+ }
+
//append midi data
mmjack_midiqueue_append(port, ident, value);
}
diff --git a/backends/jack.h b/backends/jack.h
index ca62ea5..762282b 100644
--- a/backends/jack.h
+++ b/backends/jack.h
@@ -16,6 +16,11 @@ static int mmjack_shutdown(size_t n, instance** inst);
#define JACK_DEFAULT_SERVER_NAME "default"
#define JACK_MIDIQUEUE_CHUNK 10
+#define EPN_NRPN 8
+#define EPN_PARAMETER_HI 4
+#define EPN_PARAMETER_LO 2
+#define EPN_VALUE_HI 1
+
enum /*mmjack_midi_channel_type*/ {
midi_none = 0,
midi_note = 0x90,
@@ -59,10 +64,15 @@ typedef struct /*_mmjack_port_data*/ {
double min;
uint8_t mark;
double last;
+
size_t queue_len;
size_t queue_alloc;
mmjack_midiqueue* queue;
+ uint16_t epn_control[16];
+ uint16_t epn_value[16];
+ uint8_t epn_status[16];
+
pthread_mutex_t lock;
} mmjack_port;
diff --git a/backends/jack.md b/backends/jack.md
index 3d426f3..4ff77f6 100644
--- a/backends/jack.md
+++ b/backends/jack.md
@@ -83,8 +83,11 @@ by the MIDIMonster
#### Known bugs / problems
-Extended parameter numbers (`rpn` and `nrpn` control types) can currently only be transmitted, not properly
-received as such. Support for this functionality is planned.
+MIDI extended parameter numbers (EPNs, the `rpn` and `nrpn` control types) will also generate events on the controls (CC 101 through
+98, 38 and 6) that are used as the lower layer transport. When using EPNs, mapping those controls is probably not useful.
+
+EPN control types support only the full 14-bit transfer encoding, not the shorter variant transmitting only the 7
+high-order bits. This may be changed if there is sufficient interest in the functionality.
While JACK has rudimentary capabilities for transporting OSC messages, configuring and parsing such channels
with this backend would take a great amount of dedicated syntax & code. CV ports can provide fine-grained single
diff --git a/backends/winmidi.c b/backends/winmidi.c
index 66456e8..d12dc71 100644
--- a/backends/winmidi.c
+++ b/backends/winmidi.c
@@ -402,7 +402,7 @@ static void winmidi_handle_epn(instance* inst, uint8_t chan, uint16_t control, u
ident.fields.control = data->epn_control[chan];
val.normalised = (double) data->epn_value[chan] / 16383.0;
- winmidi_enqueue_input(inst, ident,val);
+ winmidi_enqueue_input(inst, ident, val);
}
}