152
159
jack_ringbuffer_free(str->new_ports);
162
struct a2j * a2j_new(void)
159
extern void* a2j_alsa_input_thread (void*);
160
extern void* a2j_alsa_output_thread (void*);
165
void * thread_status;
162
167
struct a2j *self = calloc(1, sizeof(struct a2j));
163
168
a2j_debug("midi: new");
167
self->port_add = jack_ringbuffer_create(2*MAX_PORTS*sizeof(snd_seq_addr_t));
168
self->port_del = jack_ringbuffer_create(2*MAX_PORTS*sizeof(struct a2j_port*));
170
self->outbound_events = jack_ringbuffer_create(MAX_EVENT_SIZE*16*sizeof(struct a2j_delivery_event));
172
a2j_stream_init(self, A2J_PORT_CAPTURE);
173
a2j_stream_init(self, A2J_PORT_PLAYBACK);
171
a2j_error("calloc() failed to allocate a2j struct");
175
self->port_add = jack_ringbuffer_create(2 * MAX_PORTS * sizeof(snd_seq_addr_t));
176
if (self->port_add == NULL)
181
self->port_del = jack_ringbuffer_create(2 * MAX_PORTS * sizeof(struct a2j_port *));
182
if (self->port_del == NULL)
184
goto free_ringbuffer_add;
187
self->outbound_events = jack_ringbuffer_create(MAX_EVENT_SIZE * 16 * sizeof(struct a2j_delivery_event));
188
if (self->outbound_events == NULL)
190
goto free_ringbuffer_del;
193
if (!a2j_stream_init(self, A2J_PORT_CAPTURE))
195
goto free_ringbuffer_outbound;
198
if (!a2j_stream_init(self, A2J_PORT_PLAYBACK))
200
goto close_capture_stream;
175
203
error = snd_seq_open(&self->seq, "hw", SND_SEQ_OPEN_DUPLEX, 0);
178
206
a2j_error("failed to open alsa seq");
183
snd_seq_set_client_name(self->seq, "a2jmidid");
207
goto close_playback_stream;
210
error = snd_seq_set_client_name(self->seq, "a2jmidid");
213
a2j_error("snd_seq_set_client_name() failed");
214
goto close_seq_client;
184
217
self->port_id = snd_seq_create_simple_port(
189
222
|SND_SEQ_PORT_CAP_NO_EXPORT
191
224
,SND_SEQ_PORT_TYPE_APPLICATION);
225
if (self->port_id < 0)
227
a2j_error("snd_seq_create_simple_port() failed");
228
goto close_seq_client;
192
231
self->client_id = snd_seq_client_id(self->seq);
232
if (self->client_id < 0)
234
a2j_error("snd_seq_client_id() failed");
235
goto close_seq_client;
194
238
self->queue = snd_seq_alloc_queue(self->seq);
241
a2j_error("snd_seq_alloc_queue() failed");
242
goto close_seq_client;
195
245
snd_seq_start_queue(self->seq, self->queue, 0);
197
247
a2j_stream_attach(self->stream + A2J_PORT_CAPTURE);
198
248
a2j_stream_attach(self->stream + A2J_PORT_PLAYBACK);
200
snd_seq_nonblock(self->seq, 1);
202
snd_seq_connect_from(self->seq, self->port_id, SND_SEQ_CLIENT_SYSTEM, SND_SEQ_PORT_SYSTEM_ANNOUNCE);
250
error = snd_seq_nonblock(self->seq, 1);
253
a2j_error("snd_seq_nonblock() failed");
254
goto close_seq_client;
257
error = snd_seq_connect_from(self->seq, self->port_id, SND_SEQ_CLIENT_SYSTEM, SND_SEQ_PORT_SYSTEM_ANNOUNCE);
260
a2j_error("snd_seq_connect_from() failed");
261
goto close_seq_client;
203
264
snd_seq_drop_input(self->seq);
205
266
a2j_add_ports(&self->stream[A2J_PORT_CAPTURE]);
208
269
self->jack_client = a2j_jack_client_create(self, A2J_JACK_CLIENT_NAME, g_a2j_jack_server_name);
209
270
if (self->jack_client == NULL)
215
if (sem_init (&self->io_semaphore, 0, 0) < 0) {
216
a2j_error ("can't create IO semaphore");
275
if (sem_init(&self->io_semaphore, 0, 0) < 0)
277
a2j_error("can't create IO semaphore");
278
goto close_jack_client;
221
281
if (jack_activate(self->jack_client))
223
283
a2j_error("can't activate jack client");
225
error = jack_client_close(self->jack_client);
228
a2j_error("Cannot close jack client");
235
287
a2j_add_existing_ports(self);
237
289
g_keep_alsa_walking = true;
239
if (pthread_create (&self->alsa_input_thread, NULL, a2j_alsa_input_thread, self) < 0) {
240
fprintf (stderr, "cannot start ALSA input thread\n");
291
if (pthread_create(&self->alsa_input_thread, NULL, a2j_alsa_input_thread, self) < 0)
293
a2j_error("cannot start ALSA input thread");
245
if (pthread_create (&self->alsa_output_thread, NULL, a2j_alsa_output_thread, self) < 0) {
246
fprintf (stderr, "cannot start ALSA output thread\n");
297
if (pthread_create(&self->alsa_output_thread, NULL, a2j_alsa_output_thread, self) < 0)
299
a2j_error("cannot start ALSA output thread");
300
goto join_input_thread;
306
g_keep_alsa_walking = false; /* tell alsa threads to stop */
307
snd_seq_disconnect_from(self->seq, self->port_id, SND_SEQ_CLIENT_SYSTEM, SND_SEQ_PORT_SYSTEM_ANNOUNCE);
308
pthread_join(self->alsa_input_thread, &thread_status);
310
sem_destroy(&self->io_semaphore);
312
error = jack_client_close(self->jack_client);
315
a2j_error("Cannot close jack client");
318
snd_seq_close(self->seq);
319
close_playback_stream:
320
a2j_stream_close(self, A2J_PORT_PLAYBACK);
321
close_capture_stream:
322
a2j_stream_close(self, A2J_PORT_CAPTURE);
323
free_ringbuffer_outbound:
324
jack_ringbuffer_free(self->outbound_events);
326
jack_ringbuffer_free(self->port_del);
328
jack_ringbuffer_free(self->port_add);
335
static void a2j_destroy(struct a2j * self)
338
void * thread_status;
262
340
a2j_debug("midi: delete");
264
342
g_keep_alsa_walking = false; /* tell alsa threads to stop */
266
344
/* do something that we need to do anyway and will wake the input thread, then join */
268
345
snd_seq_disconnect_from(self->seq, self->port_id, SND_SEQ_CLIENT_SYSTEM, SND_SEQ_PORT_SYSTEM_ANNOUNCE);
269
pthread_join (self->alsa_input_thread, &alsa_status);
346
pthread_join(self->alsa_input_thread, &thread_status);
271
348
/* wake output thread and join, then destroy the semaphore */
273
sem_post (&self->io_semaphore);
274
pthread_join (self->alsa_output_thread, &alsa_status);
275
sem_destroy (&self->io_semaphore);
349
sem_post(&self->io_semaphore);
350
pthread_join(self->alsa_output_thread, &thread_status);
351
sem_destroy(&self->io_semaphore);
277
353
jack_ringbuffer_reset(self->port_add);