-
Notifications
You must be signed in to change notification settings - Fork 5
/
midijack.c
139 lines (99 loc) · 3.13 KB
/
midijack.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <jack/jack.h>
#include <jack/types.h>
#include <jack/midiport.h>
#include <jack/session.h>
#include <jack/ringbuffer.h>
//#include "midiprotocol.h"
#include "glue.h"
#define CLIENT_NAME "MIDI_JOYSTICK"
#define OUTPUT_PORT_NAME "MidiOut"
static jack_port_t *output_port;
static jack_client_t *client;
static jack_ringbuffer_t *rb;
/**
* signal handler needed to shutdown client properly
*/
static void signal_handler(int sig)
{
jack_ringbuffer_free (rb);
jack_client_close(client);
exit(0);
}
/**
* shutdown callback called by JACK if server shuts down or disconnects this client
*/
static void jack_shutdown(void *arg)
{
exit(1);
}
/**
* process callback called by JACK in special realtime thread once for each audio cycle
*/
int process (jack_nframes_t nframes, void *arg)
{
void* port_buf = jack_port_get_buffer(output_port, nframes);
struct midi_msg midi;
jack_nframes_t frame_idx;
int data_idx;
jack_midi_clear_buffer(port_buf);
for (frame_idx = 0; frame_idx < nframes; ++frame_idx) {
if (jack_ringbuffer_read(rb, (void*) &midi, sizeof(midi)) != sizeof(midi)) {
/* unable to get full midi message -> skip */
continue;
}
jack_midi_data_t midi_data[MAX_MIDI_MSG];
for (data_idx = 0; data_idx < midi.size && data_idx < MAX_MIDI_MSG; ++data_idx) {
midi_data[data_idx] = midi.msg[data_idx];
}
jack_midi_event_write(port_buf, frame_idx, midi_data, midi.size);
}
return 0;
}
int setup_jack(jack_ringbuffer_t** ringbuf, size_t ringbuf_size)
{
if ((rb = jack_ringbuffer_create(ringbuf_size)) == NULL) {
fprintf(stderr, "failed to create jack ringbuffer\n");
return -1;
}
*ringbuf = rb;
if ((client = jack_client_open(CLIENT_NAME, JackNullOption, NULL)) == NULL) {
fprintf(stderr, "failed to connect to JACK Server\n");
return -1;
}
if (jack_set_process_callback(client, process, 0) != 0) {
fprintf(stderr, "failed to register process callback\n");
return -1;
}
jack_on_shutdown(client, jack_shutdown, 0);
/* When JACK is running realtime, jack_activate() will have
* called mlockall() to lock our pages into memory. But, we
* still need to touch any newly allocated pages before
* process() starts using them. Otherwise, a page fault could
* create a delay that would force JACK to shut us down. */
memset(rb->buf, 0, rb->size);
if (!(output_port = jack_port_register(client, OUTPUT_PORT_NAME, JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0))) {
fprintf(stderr, "failed to register output port \n");
return -1;
}
/* register signal handlers for proper shutdown */
signal(SIGTERM, signal_handler);
signal(SIGINT, signal_handler);
if (jack_activate(client)) {
fprintf(stderr, "cannot activate client\n");
return -1;
}
return 0;
}
int tear_down_jack(void)
{
jack_ringbuffer_free(rb);
jack_client_close(client);
return 0;
}