It does not look like the Link/Link v2 module has a "run" connector for VCV Rack that allows me to connect to the Impromptu Clock mule's "Run" connector. The "clock" light is always blinking. Also, for "Link v2," the "reset" light always flashes per measure, such as every 4 beats in a bar. That causes the maze modules to always start from the beginning every 4 beat, so that's not going to work. The "reset" connector is only useful if a stop command is initiated. Anyway, I will give it a try along with tramp's code. Thanks.
Update:
@tramp, I tried your code and even though it works, it does not look like your code is sending a "note off" message. My current behavior is as follows:
- Press play in MUSE Sequencer and both VCV Rack and QMidiArp plays. The "gate" connector in MIDI-CV lights up.
- Press stop (same sequencer) and even though QMidiArp stops, VCV Rack keeps playing.
- Press play again and VCV Rack stops playing but QMidiArp plays. The "gate" connector in MIDI-CV turns off.
- Press stop again and both VCV Rack and QMidiArp stops playing.
So, I came up with this:
Code: Select all
#include <jack/jack.h>
#include <jack/midiport.h>
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#define min(x, y) (((x) < (y)) ? (x) : (y))
jack_client_t *client;
jack_port_t *output_port;
unsigned int ts;
int send_note_off = 0;
static void signal_handler(int sig)
{
jack_client_close(client);
fprintf(stderr, "signal received, exiting ...\n");
exit(0);
}
static int process(jack_nframes_t nframes, void *arg)
{
jack_transport_state_t transport_state = jack_transport_query(client, NULL);
int state_changed = 0;
if (ts != transport_state) {
ts = min(1,transport_state);
state_changed = 1;
}
void* port_buf = jack_port_get_buffer(output_port, nframes);
unsigned char* buffer;
jack_midi_clear_buffer(port_buf);
// Send a "note on" message once a state has changed.
// The "note on" message will not be sent again unless the
// "send_note_off" variable is set to 0.
if (state_changed && send_note_off == 0 ) {
fprintf (stderr, "Sending note on...\n");
buffer = jack_midi_event_reserve(port_buf, 0, 3);
buffer[2] = 1; /* velocity */
buffer[1] = 60; /* note C4*/
buffer[0] = 0x90; /* note on */
send_note_off = 1;
}
// After the note on process is complete, send the "note off" message.
else if(send_note_off == 1) {
fprintf (stderr, "Sending note off...\n");
buffer = jack_midi_event_reserve(port_buf, 0, 3);
buffer[2] = 1; /* velocity */
buffer[1] = 60; /* note C4*/
buffer[0] = 0x80; /* note off */
send_note_off = 0;
}
//else if ((state_changed && !ts) && note_off_process_complete == 0 ) {
// fprintf (stderr, "Sending note off...\n");
// buffer = jack_midi_event_reserve(port_buf, 0, 3);
// buffer[2] = 1; /* velocity */
// buffer[1] = 60; /* note C4*/
// buffer[0] = 0x80; /* note off */
// note_on_process_complete = 0;
// note_off_process_complete = 1;
//}
return 0;
}
int main(int narg, char **args)
{
ts = 0;
if((client = jack_client_open ("trans2midi", JackNullOption, NULL)) == 0)
{
fprintf (stderr, "JACK server not running?\n");
return 1;
}
jack_set_process_callback (client, process, 0);
output_port = jack_port_register (client, "out", JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0);
if (jack_activate(client))
{
fprintf (stderr, "cannot activate client");
return 1;
}
/* install a signal handler to properly quits jack client */
signal(SIGTERM, signal_handler);
signal(SIGINT, signal_handler);
/* run until interrupted ctrl-c*/
sleep(-1);
jack_client_close(client);
exit (0);
}
The "play" and "stop" buttons sent a MIDI note on and MIDI note off message to the client which triggers the gate connector twice and it works.
Because I don't qualify as a C++/JACK developer, I don't understand all the stuff that's in the code, but at least I do understand how MIDI messages are sent using a buffer, such as velocity, note number, and note on/off messages. And of course, I do have JACK Link for BPM and it works fine.