//Standard lib #include //memcpy #include //print error messages #include //Third party #include #include #include #include //Our own files #include "jackclient.h" #include "constants.h" #include "programstate.h" extern ProgramState programState; static jack_client_t* client; //static jack_ringbuffer_t *ringbuffer = NULL; jack_ringbuffer_t *allRingbuffers[VIS_PORTS]; jack_port_t *allPorts[VIS_PORTS]; static pthread_mutex_t msg_thread_lock = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t data_ready = PTHREAD_COND_INITIALIZER; #define RBSIZE 512 typedef struct { uint8_t buffer[128]; uint32_t size; } midimsg; int process (jack_nframes_t frames, void* arg) { void* buffer; jack_nframes_t N; jack_nframes_t i; jack_port_t* port; jack_ringbuffer_t* rb=NULL; for (int portnum=0; portnum= sizeof(midimsg)) { midimsg message; message.size = event.size; memcpy (message.buffer, event.buffer, MAX(sizeof(message.buffer), event.size)); jack_ringbuffer_write (rb, (void *) &message, sizeof(midimsg)); } } } if (pthread_mutex_trylock (&msg_thread_lock) == 0) { pthread_cond_signal (&data_ready); pthread_mutex_unlock (&msg_thread_lock); } return 0; } static void handleMessage (Note *allGUINotes, int portnum, midimsg* event) { if (event->size == 0) { return; } uint8_t type = event->buffer[0] & 0xf0; uint8_t channel = event->buffer[0] & 0xf; Note * note; switch (type) { case 0x90: //assert (event->size == 3); //printf (" note on (channel %2d): pitch %3d, velocity %3d\n", channel, event->buffer[1], event->buffer[2]); programState.portActivity[portnum] += 1; note = &allGUINotes[portnum*128 + event->buffer[1]]; note->active = 1; note->countdown = 1.0f; note->velocity = event->buffer[2]; note->pitch = event->buffer[1]; note->port = portnum; break; case 0x80: //assert (event->size == 3); //printf (" note off (channel %2d): pitch %3d, velocity %3d\n", channel, event->buffer[1], event->buffer[2]); programState.portActivity[portnum] -= 1; if (programState.portActivity[portnum] < 1) { programState.portActivity[portnum] = 0;} note = &allGUINotes[portnum*128 + event->buffer[1]]; note->countdown = 0.999f; //GUI will reduce that to 0 on its own as fade-out effect //Do NOT set to inactive. Note-Off triggers a graphical fadeout, only when that is over it is inactive. break; //case 0xb0: //assert (event->size == 3); //printf (" control change (channel %2d): controller %3d, value %3d", channel, event->buffer[1], event->buffer[2]); // break; default: break; } } void mainLoop_processMidiMessages(Note *allGUINotes) { for (int portnum=0; portnum 1.0d) { //comparing to 0 does not work programState.bpm = pos.beats_per_minute; } else { programState.bpm = 120.0d; } } void ourConnectCallback(jack_port_id_t a, jack_port_id_t b, int connect, void *arg) { //On each connection change go through our ports and check the situation. //Only the first port is enough for our purposes //TODO: optimisation opportunity: keep a list of our port ids and check that first. for (int portnum=0; portnum non-const programState.connectedPortNames[portnum] = externalPrettyName; //if (externalPrettyName) jack_free(externalPrettyName); //TODO: If I free that the name either vanishes, segfaults, is wrong or garbage or it is always the same. No matter what string copy, conversion etc. I tried if (externalType) jack_free(externalType); } else { // No Metadata for this port found programState.connectedPortNames[portnum] = connectedPorts[0]; } } else { programState.connectedPortNames[portnum] = ""; //Reset } jack_free(connectedPorts); } } void createJackClient() { int errorCode; client = jack_client_open (programState.name, JackNullOption, NULL); if (client == NULL) { fprintf (stderr, "Could not create JACK client.\n"); exit (EXIT_FAILURE); } jack_set_process_callback (client, process, 0); for (int portnum=0; portnum