website/index.html: Extend Feedback section (codeberg.org)
[a2jmidid.git] / a2jmidi_bridge.c
blobe46066eb2ab07e9bfde8a7cca4e3c273d77db46f
1 /* alsaseq2jackmidi.c
3 * copies MIDI events from an ALSA sequencer client to a JACK MIDI client
5 * Copyright (c)2005 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: gcc -Wall -o alsaseq2jackmidi alsaseq2jackmidi.c -ljack -lasound */
26 /* gcc -Wall -I/tmp/jackmidi/include -o alsaseq2jackmidi alsaseq2jackmidi.c -L/tmp/jackmidi/lib -ljack -lasound */
28 #include <stdbool.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <unistd.h>
32 #include <signal.h>
33 #include <alsa/asoundlib.h>
34 #include <jack/jack.h>
35 #include <jack/midiport.h>
36 #include <jack/ringbuffer.h>
38 snd_seq_t *seq_handle;
40 snd_midi_event_t *alsa_decoder;
42 jack_ringbuffer_t *jack_ringbuffer;
44 jack_client_t *jack_client;
45 jack_port_t *jack_midi_port;
47 int jack_write_overflows = 0,
48 old_jack_write_overflows = 0,
49 events_copied = 0,
50 old_events_copied = 0;
52 bool g_keep_walking;
54 void
55 midi_action(snd_seq_t *seq_handle)
57 snd_seq_event_t *ev;
58 static unsigned char buffer[16];
59 long count;
61 do {
62 snd_seq_event_input(seq_handle, &ev);
64 count = snd_midi_event_decode(alsa_decoder, buffer + 1, 16, ev);
65 if (count > 0 && count < 16) {
66 buffer[0] = (unsigned char)count;
67 count++;
68 if (jack_ringbuffer_write(jack_ringbuffer, (char *)buffer, count) != (jack_nframes_t)count) {
69 fprintf(stderr, "ringbuffer overflow!\n");
73 snd_seq_free_event(ev);
74 } while (snd_seq_event_input_pending(seq_handle, 0) > 0);
77 int
78 jack_callback(jack_nframes_t nframes, void *arg)
80 static unsigned char buffer[16];
81 size_t count;
82 unsigned char *p;
83 void* port_buf = jack_port_get_buffer(jack_midi_port, nframes);
85 ((void)(arg)); /* unreferenced parameter */
87 jack_midi_clear_buffer(port_buf);
89 while (jack_ringbuffer_read_space(jack_ringbuffer)) {
90 count = jack_ringbuffer_peek(jack_ringbuffer, (char*)buffer, 1);
91 if (count) {
92 count = (size_t)buffer[0];
93 if (jack_ringbuffer_read(jack_ringbuffer, (char*)buffer, count + 1) != count + 1) {
94 fprintf(stderr, "???? short read from ringbuffer!\n"); /* shouldn't happen */
95 } else {
96 /* -FIX- this should have the frame time of the event, instead of '0': */
97 p = jack_midi_event_reserve(port_buf, 0, count);
98 if (p) {
99 memcpy(p, buffer + 1, count);
100 events_copied++;
101 } else
102 jack_write_overflows++;
107 return 0;
110 static
111 void
112 jack_shutdown(
113 void * arg)
115 ((void)(arg)); /* unreferenced parameter */
116 fprintf(stderr, "JACK shutdown notification received.\n");
117 g_keep_walking = false;
120 static
121 void
122 sigint_handler(
123 int i)
125 ((void)(i)); /* unreferenced parameter */
126 g_keep_walking = false;
130 main(int argc, char *argv[])
132 int portid;
133 int npfd;
134 struct pollfd *pfd;
135 const char * client_name;
136 jack_status_t status;
138 if (argc == 2)
140 client_name = argv[1];
142 else
144 client_name = "a2j_bridge";
147 /* Create ALSA sequencer client */
148 if (snd_seq_open(&seq_handle, "hw", SND_SEQ_OPEN_INPUT, 0) < 0) {
149 fprintf(stderr, "Error opening ALSA sequencer.\n");
150 exit(1);
152 snd_seq_set_client_name(seq_handle, client_name);
153 if ((portid = snd_seq_create_simple_port(seq_handle, "playback",
154 SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE,
155 SND_SEQ_PORT_TYPE_HARDWARE)) < 0) {
156 fprintf(stderr, "Error creating sequencer port.\n");
157 exit(1);
159 npfd = snd_seq_poll_descriptors_count(seq_handle, POLLIN);
160 pfd = (struct pollfd *)alloca(npfd * sizeof(struct pollfd));
161 snd_seq_poll_descriptors(seq_handle, pfd, npfd, POLLIN);
163 /* Create ALSA snd_seq_event_t decoder */
164 if (snd_midi_event_new(16, &alsa_decoder)) {
165 fprintf(stderr, "Error initializing ALSA MIDI decoder!\n");
166 exit(1);
169 snd_midi_event_reset_decode(alsa_decoder);
170 snd_midi_event_no_status(alsa_decoder, 1);
172 /* Create interthread ringbuffer */
173 jack_ringbuffer = jack_ringbuffer_create(2048);
174 if (!jack_ringbuffer) {
175 fprintf(stderr, "Failed to create ringbuffer!\n");
176 exit(1);
178 jack_ringbuffer_reset(jack_ringbuffer);
180 /* Create JACK MIDI client */
181 jack_client = jack_client_open(client_name, 0, &status);
182 if (jack_client == 0) {
183 fprintf(stderr, "Failed to connect to JACK server!\n");
184 exit(1);
187 jack_midi_port = jack_port_register (jack_client, "capture",
188 JACK_DEFAULT_MIDI_TYPE,
189 JackPortIsOutput, 0);
190 if (!jack_midi_port) {
191 fprintf(stderr, "Failed to create JACK MIDI port!\n");
192 exit(1);
195 jack_set_process_callback(jack_client, jack_callback, 0);
197 g_keep_walking = true;
199 jack_on_shutdown(jack_client, jack_shutdown, NULL);
201 signal(SIGINT, &sigint_handler);
202 signal(SIGTERM, &sigint_handler);
204 if (jack_activate(jack_client)) {
205 fprintf(stderr, "Failed to activate JACK client!\n");
206 exit(1);
209 while (g_keep_walking) {
210 if (poll(pfd, npfd, 1000) > 0) {
211 midi_action(seq_handle);
213 if (jack_write_overflows != old_jack_write_overflows) {
214 old_jack_write_overflows = jack_write_overflows;
215 fprintf(stderr, "JACK port write overflow count now %d\n", jack_write_overflows);
217 // if (events_copied != old_events_copied) {
218 // old_events_copied = events_copied;
219 // fprintf(stderr, "%d events copied\n", events_copied);
220 // }
223 /* -FIX- provide a way to cleanly exit, and clean up! */
224 jack_client_close(jack_client);
225 jack_ringbuffer_free(jack_ringbuffer);
226 snd_seq_close(seq_handle);
228 return 0;