Permalink
Browse files

Implement "Controller Feedback" MIDI output and associated ring-buffe…

…r functions.
  • Loading branch information...
jofemodo committed Jan 8, 2019
1 parent 908cc58 commit e5859ecced2dd98cc222366e7c4235a4ef7387d0
Showing with 137 additions and 23 deletions.
  1. +3 −0 zyncoder.c
  2. +116 −11 zynmidirouter.c
  3. +18 −12 zynmidirouter.h
@@ -388,7 +388,10 @@ void send_zyncoder(uint8_t i) {
struct zyncoder_st *zyncoder = zyncoders + i;
if (zyncoder->enabled==0) return;
if (zyncoder->midi_ctrl>0) {
//Send to MIDI output
zynmidi_send_ccontrol_change(zyncoder->midi_chan,zyncoder->midi_ctrl,zyncoder->value);
//Send to MIDI controller feedback => TODO: Reverse Mapping!!
ctrlfb_send_ccontrol_change(zyncoder->midi_chan,zyncoder->midi_ctrl,zyncoder->value);
//printf("SEND MIDI CHAN %d, CTRL %d = %d\n",zyncoder->midi_chan,zyncoder->midi_ctrl,zyncoder->value);
} else if (zyncoder->osc_lo_addr!=NULL && zyncoder->osc_path[0]) {
if (zyncoder->step >= 8) {
@@ -600,6 +600,7 @@ int init_jack_midi(char *name) {
//Init Output Ports
if (!zmop_init(ZMOP_MAIN,"main_out",-1)) return 0;
if (!zmop_init(ZMOP_NET,"net_out",-1)) return 0;
if (!zmop_init(ZMOP_CTRL,"ctrl_out",-1)) return 0;
char port_name[12];
for (i=0;i<16;i++) {
sprintf(port_name,"ch%d_out",i);
@@ -622,17 +623,27 @@ int init_jack_midi(char *name) {
}
// ZMIP_CTRL is not routed to any output port, only captured by Zynthian UI

//Init Ring-Buffers
jack_ring_output_buffer = jack_ringbuffer_create(JACK_MIDI_BUFFER_SIZE);
// lock the buffer into memory, this is *NOT* realtime safe, do it before using the buffer!
if (jack_ringbuffer_mlock(jack_ring_output_buffer)) {
fprintf (stderr, "ZynMidiRouter: Error locking memory for jack ring output buffer.\n");
fprintf (stderr, "ZynMidiRouter: Error locking memory for internal output ring-buffer.\n");
return 0;
}
jack_ring_ctrlfb_buffer = jack_ringbuffer_create(JACK_MIDI_BUFFER_SIZE);
// lock the buffer into memory, this is *NOT* realtime safe, do it before using the buffer!
if (jack_ringbuffer_mlock(jack_ring_ctrlfb_buffer)) {
fprintf (stderr, "ZynMidiRouter: Error locking memory for controller feedback ring-buffer.\n");
return 0;
}

//Init Jack Process
jack_set_process_callback(jack_client, jack_process, 0);
if (jack_activate(jack_client)) {
fprintf (stderr, "ZynMidiRouter: Error activating jack client.\n");
return 0;
}

return 1;
}

@@ -982,9 +993,15 @@ int jack_process(jack_nframes_t nframes, void *arg) {
//---------------------------------
//Internal MIDI Thru
//---------------------------------
//Forward internal MIDI data from ringbuffer to all ZMOPS
//Forward internal MIDI data from ringbuffer to all ZMOPS except ZMOP_CTRL
if (forward_internal_midi_data()<0) return -1;

//---------------------------------
//MIDI Controller Feedback
//---------------------------------
//Forward Controller Feedback MIDI data from ringbuffer to ZMOP_CTRL
if (forward_ctrlfb_midi_data()<0) return -1;

//---------------------------------
//MIDI Output
//---------------------------------
@@ -998,43 +1015,47 @@ int jack_process(jack_nframes_t nframes, void *arg) {
}

//-----------------------------------------------------
// MIDI Internal Input Event Buffer <= UI and internal
// MIDI Internal Input <= UI and internal
//-----------------------------------------------------

//------------------------------
// Event Ring-Buffer Management
//------------------------------

uint8_t internal_midi_data[JACK_MIDI_BUFFER_SIZE];

int write_internal_midi_event(uint8_t *event_buffer, int event_size) {
if (jack_ringbuffer_write_space(jack_ring_output_buffer)>=event_size) {
if (jack_ringbuffer_write(jack_ring_output_buffer, event_buffer, event_size)!=event_size) {
fprintf (stderr, "ZynMidiRouter: Error writing jack ring output buffer: INCOMPLETE\n");
fprintf (stderr, "ZynMidiRouter: Error writing internal output ring-buffer: INCOMPLETE\n");
return 0;
}
}
else {
fprintf (stderr, "ZynMidiRouter: Error writing jack ring output buffer: FULL\n");
fprintf (stderr, "ZynMidiRouter: Error writing internal output ring-buffer: FULL\n");
return 0;
}
return 1;
}

//Get MIDI data from ringbuffer
//Get MIDI data from ringbuffer and forward to all ZMOPS except ZMOP_CTRL
int forward_internal_midi_data() {
int nb=jack_ringbuffer_read_space(jack_ring_output_buffer);
if (jack_ringbuffer_read(jack_ring_output_buffer, internal_midi_data, nb)!=nb) {
fprintf (stderr, "ZynMidiRouter: Error reading midi data from jack ring output buffer: %d bytes\n", nb);
fprintf (stderr, "ZynMidiRouter: Error reading midi data from internal output ring-buffer: %d bytes\n", nb);
return -1;
}
int i;
for (i=0;i<MAX_NUM_ZMOPS;i++) {
for (i=0;i<ZMOP_CTRL;i++) {
memcpy(zmops[i].data+zmops[i].n_data, internal_midi_data, nb);
zmops[i].n_data+=nb;
}
return nb;
}

//-----------------------------------------------------------------------------
// MIDI Internal Input: Send Functions <= UI and internal
//-----------------------------------------------------------------------------
//------------------------------
// Send Functions
//------------------------------

int zynmidi_send_note_off(uint8_t chan, uint8_t note, uint8_t vel) {
uint8_t buffer[3];
@@ -1082,6 +1103,90 @@ int zynmidi_send_master_ccontrol_change(uint8_t ctrl, uint8_t val) {
}
}


//-----------------------------------------------------
// MIDI Controller Feedback <= UI and internal
//-----------------------------------------------------

//------------------------------
// Event Ring-Buffer Management
//------------------------------

uint8_t ctrlfb_midi_data[JACK_MIDI_BUFFER_SIZE];

int write_ctrlfb_midi_event(uint8_t *event_buffer, int event_size) {
if (jack_ringbuffer_write_space(jack_ring_ctrlfb_buffer)>=event_size) {
if (jack_ringbuffer_write(jack_ring_ctrlfb_buffer, event_buffer, event_size)!=event_size) {
fprintf (stderr, "ZynMidiRouter: Error writing controller feedback ring-buffer: INCOMPLETE\n");
return 0;
}
}
else {
fprintf (stderr, "ZynMidiRouter: Error writing controller feedback ring-buffer: FULL\n");
return 0;
}
return 1;
}

//Get MIDI data from ringbuffer and forward to all ZMOPS except ZMOP_CTRL
int forward_ctrlfb_midi_data() {
int nb=jack_ringbuffer_read_space(jack_ring_ctrlfb_buffer);
if (jack_ringbuffer_read(jack_ring_ctrlfb_buffer, ctrlfb_midi_data, nb)!=nb) {
fprintf (stderr, "ZynMidiRouter: Error reading midi data from controller feedback ring-buffer: %d bytes\n", nb);
return -1;
}

memcpy(zmops[ZMOP_CTRL].data+zmops[ZMOP_CTRL].n_data, ctrlfb_midi_data, nb);
zmops[ZMOP_CTRL].n_data+=nb;

return nb;
}

//------------------------------
// Send Functions
//------------------------------

int ctrlfb_send_note_off(uint8_t chan, uint8_t note, uint8_t vel) {
uint8_t buffer[3];
buffer[0] = 0x80 + (chan & 0x0F);
buffer[1] = note;
buffer[2] = vel;
return write_ctrlfb_midi_event(buffer,3);
}

int ctrlfb_send_note_on(uint8_t chan, uint8_t note, uint8_t vel) {
uint8_t buffer[3];
buffer[0] = 0x90 + (chan & 0x0F);
buffer[1] = note;
buffer[2] = vel;
return write_ctrlfb_midi_event(buffer,3);
}

int ctrlfb_send_ccontrol_change(uint8_t chan, uint8_t ctrl, uint8_t val) {
uint8_t buffer[3];
buffer[0] = 0xB0 + (chan & 0x0F);
buffer[1] = ctrl;
buffer[2] = val;
return write_ctrlfb_midi_event(buffer,3);
}

int ctrlfb_send_program_change(uint8_t chan, uint8_t prgm) {
uint8_t buffer[3];
buffer[0] = 0xC0 + (chan & 0x0F);
buffer[1] = prgm;
buffer[2] = 0;
return write_ctrlfb_midi_event(buffer,3);
}

int ctrlfb_send_pitchbend_change(uint8_t chan, uint16_t pb) {
uint8_t buffer[3];
buffer[0] = 0xE0 + (chan & 0x0F);
buffer[1] = pb & 0x7F;
buffer[2] = (pb >> 7) & 0x7F;
return write_ctrlfb_midi_event(buffer,3);
}


//-----------------------------------------------------------------------------
// MIDI Internal Ouput Events Buffer => UI
//-----------------------------------------------------------------------------
@@ -177,7 +177,8 @@ uint8_t get_midi_filter_cc_swap(uint8_t chan, uint8_t num);
#define ZMOP_CH13 15
#define ZMOP_CH14 16
#define ZMOP_CH15 17
#define MAX_NUM_ZMOPS 18
#define ZMOP_CTRL 18
#define MAX_NUM_ZMOPS 19

#define ZMIP_MAIN 0
#define ZMIP_NET 1
@@ -226,22 +227,18 @@ int end_jack_midi();
int jack_process(jack_nframes_t nframes, void *arg);

//-----------------------------------------------------------------------------
// MIDI Input Events Buffer Management
// MIDI Input Events Buffer Management and Send functions
//-----------------------------------------------------------------------------

#define ZYNMIDI_BUFFER_SIZE 256
#define ZYNMIDI_BUFFER_SIZE 1024

//-----------------------------------------------------
// MIDI Internal Input Event Buffer <= UI and internal
// MIDI Internal Input <= UI and internal
//-----------------------------------------------------

jack_ringbuffer_t *jack_ring_output_buffer;
int write_internal_midi_event(uint8_t *event, int event_size);

//-----------------------------------------------------------------------------
// MIDI Internal Input: Send Functions <= UI and internal
//-----------------------------------------------------------------------------

int zynmidi_send_note_off(uint8_t chan, uint8_t note, uint8_t vel);
int zynmidi_send_note_on(uint8_t chan, uint8_t note, uint8_t vel);
int zynmidi_send_ccontrol_change(uint8_t chan, uint8_t ctrl, uint8_t val);
@@ -250,6 +247,19 @@ int zynmidi_send_pitchbend_change(uint8_t chan, uint16_t pb);

int zynmidi_send_master_ccontrol_change(uint8_t ctrl, uint8_t val);

//-----------------------------------------------------
// MIDI Controller Feedback <= UI and internal
//-----------------------------------------------------

jack_ringbuffer_t *jack_ring_ctrlfb_buffer;
int write_ctrlfb_midi_event(uint8_t *event, int event_size);

int ctrlfb_send_note_off(uint8_t chan, uint8_t note, uint8_t vel);
int ctrlfb_send_note_on(uint8_t chan, uint8_t note, uint8_t vel);
int ctrlfb_send_ccontrol_change(uint8_t chan, uint8_t ctrl, uint8_t val);
int ctrlfb_send_program_change(uint8_t chan, uint8_t prgm);
int ctrlfb_send_pitchbend_change(uint8_t chan, uint16_t pb);

//-----------------------------------------------------------------------------
// MIDI Internal Ouput Events Buffer => UI
//-----------------------------------------------------------------------------
@@ -258,10 +268,6 @@ int init_zynmidi_buffer();
int write_zynmidi(uint32_t ev);
uint32_t read_zynmidi();

//-----------------------------------------------------------------------------
// MIDI Internal Output: Send Functions => UI
//-----------------------------------------------------------------------------

int write_zynmidi_ccontrol_change(uint8_t chan, uint8_t ctrl, uint8_t val);

//-----------------------------------------------------------------------------

0 comments on commit e5859ec

Please sign in to comment.