-u commandline option
[a2jmidid.git] / j2amidi_bridge.c
blobde07957de000e8407f9b9f6f177f53be66422db2
1 /* jackmidi2alsaseq.c
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,
21 * MA 02111-1307, USA.
24 /* compile with LASH:
26 gcc -ansi -pedantic -O2 -Wall -o jackmidi2alsaseq jackmidi2alsaseq.c `pkg-config --cflags --libs jack alsa lash-1.0`
28 or without LASH:
30 gcc -ansi -pedantic -O2 -Wall -o jackmidi2alsaseq jackmidi2alsaseq.c `pkg-config --cflags --libs jack alsa` -DNO_LASH
35 #include <sched.h>
36 #include <signal.h>
37 #if !defined(__USE_BSD)
38 #define __USE_BSD /* to get snprintf() */
39 #endif
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <sys/time.h>
43 #if !defined(__USE_POSIX199309)
44 #define __USE_POSIX199309
45 #endif
46 #include <time.h>
47 #include <unistd.h>
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;
57 int keep_running = 1;
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;
63 int portid;
64 int queue_id;
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();
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;
80 if (argc == 2)
82 client_name = argv[1];
84 else
86 client_name = "j2a_bridge";
89 /* Initialise connections and signal handlers */
90 if (!(init_alsa(client_name) && init_jack(client_name)))
91 exit(1);
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) &&
106 keep_running) {
107 output_event();
110 nanosleep(&sleep_time, NULL);
113 /* Clean up */
114 jack_client_close(jack_client);
115 jack_ringbuffer_free(jack_ringbuffer);
116 snd_seq_close(seq_handle);
118 return 0;
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");
127 return 0;
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");
137 return 0;
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);
145 return 1;
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");
156 return 0;
159 /* Create a MIDI input port */
160 jack_midi_port = jack_port_register(jack_client, "playback",
161 JACK_DEFAULT_MIDI_TYPE,
162 JackPortIsInput, 0);
163 if (!jack_midi_port) {
164 fprintf(stderr, "Failed to create JACK MIDI port!\n");
165 return 0;
168 /* Initialise the ringbuffer */
169 jack_ringbuffer = jack_ringbuffer_create(2048);
170 if (!jack_ringbuffer) {
171 fprintf(stderr, "Failed to create ringbuffer!\n");
172 return 0;
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");
180 return 0;
183 return 1;
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 keep_running = 0;
193 int jack_callback(jack_nframes_t nframes, void *arg) {
194 jack_ringbuffer_t* jack_ringbuffer = arg;
195 void* midi_port_buf = jack_port_get_buffer(jack_midi_port, nframes);
196 jack_midi_event_t jack_midi_event;
197 jack_nframes_t jack_midi_event_index = 0;
198 jack_nframes_t jack_midi_event_count = jack_midi_get_event_count(midi_port_buf);
200 /* Loop while there are MIDI events in the input buffer */
201 while (jack_midi_event_index < jack_midi_event_count) {
202 jack_midi_event_get(&jack_midi_event, midi_port_buf,
203 jack_midi_event_index);
204 jack_midi_event_index++;
206 /* Check if we have enough space in the ringbuffer for the event */
207 if (jack_ringbuffer_write_space(jack_ringbuffer) <
208 jack_midi_event.size + sizeof(size_t)) {
209 ++ringbuffer_overflows;
212 /* Write the event to the ringbuffer */
213 else {
214 jack_ringbuffer_write(jack_ringbuffer,
215 (char*)&jack_midi_event.size,
216 sizeof(size_t));
217 jack_ringbuffer_write(jack_ringbuffer,
218 (char*)jack_midi_event.buffer,
219 jack_midi_event.size);
223 return 0;
227 void output_event() {
228 size_t event_size;
229 static char event_buffer[1024];
230 snd_seq_event_t alsa_event;
231 static struct timespec sleep_time = { 0, 1e4 };
233 /* Read the size of the MIDI data and wait until we have that much
234 data to read on the ringbuffer */
235 jack_ringbuffer_read(jack_ringbuffer, (char*)&event_size, sizeof(size_t));
236 while (jack_ringbuffer_read_space(jack_ringbuffer) < event_size &&
237 keep_running)
238 nanosleep(&sleep_time, NULL);
240 /* Read the MIDI data and make an ALSA MIDI event from it */
241 jack_ringbuffer_read(jack_ringbuffer, event_buffer, event_size);
242 snd_seq_ev_clear(&alsa_event);
243 if (snd_midi_event_encode(alsa_encoder, (unsigned char*)event_buffer,
244 event_size, &alsa_event)) {
245 snd_seq_ev_set_source(&alsa_event, portid);
246 snd_seq_ev_set_subs(&alsa_event);
247 snd_seq_ev_schedule_tick(&alsa_event, queue_id, 1, 0);
248 snd_seq_event_output_direct(seq_handle, &alsa_event);