these are my specific Jack MIDI lines:
const char* client_name {"Commander"};
jack_client_t* client {NULL};
jack_port_t* output_port {NULL};
jack_nframes_t local_nframes = {0};
int process(jack_nframes_t nframes, [[maybe_unused]]void* arg) {/*{{{*/
local_nframes = nframes;
return 0;
}/*}}}*/
void Keyboard::connect() noexcept{/*{{{*/
// Open a connection to the JACK server
client = jack_client_open(client_name, JackNullOption, NULL);
if (client == NULL) {
std::cerr << "Failed to open " << client_name << "client at Keyboard::connect()\n";
std::exit(EXIT_FAILURE);
}
// Create a MIDI output port
output_port = jack_port_register(client, "output", JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0);
if (output_port == NULL) {
// Failed to create output port
jack_client_close(client);
std::cerr << "Failed to open " << client_name << "port at Keyboard::connect()\n";
std::exit(EXIT_FAILURE);
}
// Set the process callback function
jack_set_process_callback(client, process, 0);
// Activate the client
if (jack_activate(client) != 0) {
// Failed to activate client
jack_port_unregister(client, output_port);
jack_client_close(client);
std::cerr << "Failed to activate " << client_name << "client at Keyboard::connect()\n";
std::exit(EXIT_FAILURE);
}
MIDI = Switch::ON;
}/*}}}*/
void Keyboard::dump_performance(const Performance& _Performance) noexcept/*{{{*/
{
set_performance_buffer(_Performance); // Pass to the buffer
// Sleep
static struct timespec keyboardTimer;
keyboardTimer.tv_sec = 0;
keyboardTimer.tv_nsec = 200000000;
// Change page
[[maybe_unused]]jack_midi_data_t combiSysEx[7] = {0xF0, 0x42, 0x30, 0x7A, 0x4E, 0x00, 0xF7};
[[maybe_unused]]jack_midi_data_t timbreSysEx[7] = {0xF0, 0x42, 0x30, 0x7A, 0x4E, 0x01, 0xF7};
// MIDI Ch = msb[0], lsb[0], pc[0] are the same, only the last digit changes
[[maybe_unused]]jack_midi_data_t msb[3] = {0xB0, 0x00, 0x3F};
[[maybe_unused]]jack_midi_data_t lsb[3] = {0xB0, 0x20, 0x00};
[[maybe_unused]]jack_midi_data_t pc[2] = {0xC0, 0x00};
// Adjustment
lsb[2] = performance_buffer.patch.bnk - 65; /*LSB*/
pc[1] = performance_buffer.patch.num; /*PC*/
// Retrieve the output port buffer
void* port_buffer = jack_port_get_buffer(output_port, local_nframes);
// Clear the port buffer before writing MIDI events
jack_midi_clear_buffer(port_buffer);
// Send the MIDI messages to the output port
if (output_port != nullptr) {
jack_midi_event_write(port_buffer, 0, combiSysEx, sizeof(combiSysEx));
jack_midi_event_write(port_buffer, 0, timbreSysEx, sizeof(timbreSysEx));
jack_midi_event_write(port_buffer, 0, msb, sizeof(msb));
jack_midi_event_write(port_buffer, 0, lsb, sizeof(lsb));
jack_midi_event_write(port_buffer, 0, pc, sizeof(pc));
}
// Sleep
nanosleep(&keyboardTimer, NULL);
set_scene(performance_buffer.default_scene);
//dump_scene();
}/*}}}*/
void Keyboard::disconnect() noexcept {/*{{{*/
// Deactivate, unregister, and close the client
jack_deactivate(client);
jack_port_unregister(client, output_port);
jack_client_close(client);
// Set MIDI switch to OFF or perform any necessary cleanup
MIDI = Switch::OFF;
}/*}}}*/
When the first jack_midi_event_write() function from Keyboard::dump_performance() is called, it correctly send the message but infinite times. There is no way to stop. Even if i disconnect and reconnect to the other client. I have to disconnect my client.
There is no loop anywhere in my program. In fact the each message is repeated indefinedly and the program continues without problem. Is like the port_buffer continues sending all his received messages.
REAPER receiving again and again the same messages
How could I solve it?
- Recorded the output of my program into Reaper and notice the brutal looping of the same messages.
- Try to send just one message
Nothing happens
In fact, it was a misunderstood of the JACK mechanism and the behaviour of the Jack callback functions.
The
process()function is designed to containt all the data input and output messages. Also, it works asynchroniusly from the execution of the program (runs independently our program workflow), and at last but not least: the output port buffer works as an independent antena that will send again and again his received messages. So there are the key conepts.The solution? Put all the
jack_midi_event_write()calls inside the acurate callback functions and ensure with flags that the messages will be called by jack just once. So the creation of boolean flags that settruewhen we want the action andfalseinside the callback function is a good approach. Also remember, let's declare this flag variables asvolatileThank you very much