3 * copies MIDI events from a JACK MIDI client to an ALSA sequencer client
5 * Copyright (C) 2005 Lars Luthman, based on alsaseq2jackmidi.c by Sean Bolton.
6 * Copyright (c) 2008,2009 Nedko Arnaudov <nedko@arnaudov.name>
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
13 * This program is distributed in the hope that it will be
14 * useful, but WITHOUT ANY WARRANTY; without even the implied
15 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
16 * PURPOSE. See the GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public
19 * License along with this program; if not, write to the Free
20 * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
26 gcc -ansi -pedantic -O2 -Wall -o jackmidi2alsaseq jackmidi2alsaseq.c `pkg-config --cflags --libs jack alsa lash-1.0`
30 gcc -ansi -pedantic -O2 -Wall -o jackmidi2alsaseq jackmidi2alsaseq.c `pkg-config --cflags --libs jack alsa` -DNO_LASH
37 #if !defined(__USE_BSD)
38 #define __USE_BSD /* to get snprintf() */
43 #if !defined(__USE_POSIX199309)
44 #define __USE_POSIX199309
49 #include <alsa/asoundlib.h>
50 #include <jack/jack.h>
51 #include <jack/midiport.h>
52 #include <jack/ringbuffer.h>
55 jack_client_t
*jack_client
;
56 jack_port_t
*jack_midi_port
;
58 unsigned long int ringbuffer_overflows
= 0;
59 snd_seq_t
*seq_handle
;
60 snd_midi_event_t
*alsa_encoder
;
61 jack_ringbuffer_t
*jack_ringbuffer
;
62 char* jack_name
= NULL
;
67 int init_alsa(const char * client_name
);
68 int init_jack(const char * client_name
);
69 void sigint_handler(int i
);
70 int jack_callback(jack_nframes_t nframes
, void *arg
);
71 void output_event(void);
74 int main(int argc
, char **argv
) {
76 unsigned long old_ringbuffer_overflows
= 0;
77 struct timespec sleep_time
= { 0, 1e6
};
78 const char * client_name
;
82 client_name
= argv
[1];
86 client_name
= "j2a_bridge";
89 /* Initialise connections and signal handlers */
90 if (!(init_alsa(client_name
) && init_jack(client_name
)))
92 signal(SIGINT
, &sigint_handler
);
93 signal(SIGTERM
, &sigint_handler
);
95 /* Loop until we get a SIGINT or SIGTERM */
96 while (keep_running
) {
98 /* Report overflows */
99 if (old_ringbuffer_overflows
!= ringbuffer_overflows
) {
100 fprintf(stderr
, "Overflow, MIDI events are coming in too fast!\n");
101 old_ringbuffer_overflows
= ringbuffer_overflows
;
104 /* Write MIDI events to the ALSA sequencer port */
105 while (jack_ringbuffer_read_space(jack_ringbuffer
) >= sizeof(size_t) &&
110 nanosleep(&sleep_time
, NULL
);
114 jack_client_close(jack_client
);
115 jack_ringbuffer_free(jack_ringbuffer
);
116 snd_seq_close(seq_handle
);
122 int init_alsa(const char * client_name
) {
124 /* Get a sequencer handle */
125 if (snd_seq_open(&seq_handle
, "hw", SND_SEQ_OPEN_OUTPUT
, 0) < 0) {
126 fprintf(stderr
, "Error opening ALSA sequencer.\n");
129 snd_seq_set_client_name(seq_handle
, client_name
);
131 /* Create an output port */
132 if ((portid
= snd_seq_create_simple_port(seq_handle
, "capture",
133 SND_SEQ_PORT_CAP_READ
|
134 SND_SEQ_PORT_CAP_SUBS_READ
,
135 SND_SEQ_PORT_TYPE_HARDWARE
)) < 0){
136 fprintf(stderr
, "Error creating sequencer port.\n");
140 /* Initialise miscellaneous other stuff */
141 queue_id
= snd_seq_alloc_queue(seq_handle
);
142 snd_midi_event_new(1024, &alsa_encoder
);
143 snd_seq_start_queue(seq_handle
, queue_id
, NULL
);
149 int init_jack(const char * client_name
) {
150 jack_status_t status
;
152 /* Create a JACK client */
153 jack_client
= jack_client_open(client_name
, 0, &status
);
154 if (jack_client
== 0) {
155 fprintf(stderr
, "Failed to connect to JACK server!\n");
159 /* Create a MIDI input port */
160 jack_midi_port
= jack_port_register(jack_client
, "playback",
161 JACK_DEFAULT_MIDI_TYPE
,
163 if (!jack_midi_port
) {
164 fprintf(stderr
, "Failed to create JACK MIDI port!\n");
168 /* Initialise the ringbuffer */
169 jack_ringbuffer
= jack_ringbuffer_create(2048);
170 if (!jack_ringbuffer
) {
171 fprintf(stderr
, "Failed to create ringbuffer!\n");
174 jack_ringbuffer_reset(jack_ringbuffer
);
176 /* Set process callback function and activate */
177 jack_set_process_callback(jack_client
, jack_callback
, jack_ringbuffer
);
178 if (jack_activate(jack_client
)) {
179 fprintf(stderr
, "Failed to activate JACK client!\n");
187 /* This is just so we can clean up if the user presses Ctrl-C in the shell */
188 void sigint_handler(int i
) {
189 ((void)(i
)); /* unreferenced parameter */
194 int jack_callback(jack_nframes_t nframes
, void *arg
) {
195 jack_ringbuffer_t
* jack_ringbuffer
= arg
;
196 void* midi_port_buf
= jack_port_get_buffer(jack_midi_port
, nframes
);
197 jack_midi_event_t jack_midi_event
;
198 jack_nframes_t jack_midi_event_index
= 0;
199 jack_nframes_t jack_midi_event_count
= jack_midi_get_event_count(midi_port_buf
);
201 /* Loop while there are MIDI events in the input buffer */
202 while (jack_midi_event_index
< jack_midi_event_count
) {
203 jack_midi_event_get(&jack_midi_event
, midi_port_buf
,
204 jack_midi_event_index
);
205 jack_midi_event_index
++;
207 /* Check if we have enough space in the ringbuffer for the event */
208 if (jack_ringbuffer_write_space(jack_ringbuffer
) <
209 jack_midi_event
.size
+ sizeof(size_t)) {
210 ++ringbuffer_overflows
;
213 /* Write the event to the ringbuffer */
215 jack_ringbuffer_write(jack_ringbuffer
,
216 (char*)&jack_midi_event
.size
,
218 jack_ringbuffer_write(jack_ringbuffer
,
219 (char*)jack_midi_event
.buffer
,
220 jack_midi_event
.size
);
228 void output_event(void) {
230 static char event_buffer
[1024];
231 snd_seq_event_t alsa_event
;
232 static struct timespec sleep_time
= { 0, 1e4
};
234 /* Read the size of the MIDI data and wait until we have that much
235 data to read on the ringbuffer */
236 jack_ringbuffer_read(jack_ringbuffer
, (char*)&event_size
, sizeof(size_t));
237 while (jack_ringbuffer_read_space(jack_ringbuffer
) < event_size
&&
239 nanosleep(&sleep_time
, NULL
);
241 /* Read the MIDI data and make an ALSA MIDI event from it */
242 jack_ringbuffer_read(jack_ringbuffer
, event_buffer
, event_size
);
243 snd_seq_ev_clear(&alsa_event
);
244 if (snd_midi_event_encode(alsa_encoder
, (unsigned char*)event_buffer
,
245 event_size
, &alsa_event
)) {
246 snd_seq_ev_set_source(&alsa_event
, portid
);
247 snd_seq_ev_set_subs(&alsa_event
);
248 snd_seq_ev_schedule_tick(&alsa_event
, queue_id
, 1, 0);
249 snd_seq_event_output_direct(seq_handle
, &alsa_event
);