gjackspa: add a mnemonic 'D' for the main button
[ng-jackspa.git] / jackspa.c
blob2e4b2390d842ced7c2f20caafbf26ed8b42d82eb
1 /* jackspa.c - LADSPA plugin instance with JACK audio ports
2 * Copyright © 2007 Nick Thomas
3 * Copyright © 2013 Géraud Meyer <graud@gmx.com>
5 * jackspa.c is part of ng-jackspa.
7 * ng-jackpsa is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License version 2 as published by the
9 * Free Software Foundation.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include <dlfcn.h>
21 #include <errno.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include "jackspa.h"
27 /* Finds the plugin descriptor with the given ID in the given object file,
28 * storing it in state->descriptor. Returns 1 on success. On failure, returns 0
29 * and sets *error to an appropriate error message.
31 int find_plugin(state_t *state, char *file, int id, const char **error)
33 int err = 0;
34 int i;
35 void *library;
36 LADSPA_Descriptor *(*descriptor_fun)(unsigned long index);
37 LADSPA_Descriptor *descriptor;
39 /* Open the library. */
40 library = dlopen(file, RTLD_LAZY);
41 if (!library)
42 err = 1, *error = dlerror();
44 /* Find the ladspa_descriptor() function. */
45 if (!err) {
46 descriptor_fun = (LADSPA_Descriptor *(*)(unsigned long))
47 dlsym(library, "ladspa_descriptor");
48 if (!descriptor_fun)
49 err = 1, *error = dlerror();
52 /* Find the appropriate descriptor. */
53 for (i = 0; !err; i++) {
54 descriptor = descriptor_fun(i);
56 if (!descriptor)
57 err = 1, *error = "no such plugin index in the given file";
58 else if ((int)descriptor->UniqueID == id) {
59 state->descriptor = descriptor;
60 break;
64 return !err;
67 /* The JACK processing callback. */
68 int process(jack_nframes_t nframes, void *arg)
70 state_t *state = (state_t *)arg;
71 int i, j;
72 float *buffer = state->control_port_buffer;
74 /* Connect audio ports and copy control port values. */
75 for (i = 0; i < (int)state->descriptor->PortCount; i++)
76 if ( LADSPA_IS_PORT_CONTROL(state->descriptor->PortDescriptors[i]) &&
77 LADSPA_IS_PORT_INPUT(state->descriptor->PortDescriptors[i]) )
78 for (j = 0; j < (int)nframes; j++, buffer++)
79 *buffer = state->control_port_values[i];
80 else
81 state->descriptor->connect_port
82 ( state->handle, i,
83 (float *)jack_port_get_buffer(state->ports[i], nframes) );
85 /* Run the plugin. */
86 state->descriptor->run(state->handle, nframes);
88 return 0;
91 /* The JACK buffer size callback. */
92 int buffer_size(jack_nframes_t nframes, void *arg)
94 state_t *state = (state_t *)arg;
95 float *buffer;
96 int i;
98 state->control_port_buffer = (float *)realloc
99 ( state->control_port_buffer,
100 state->num_control_ports * nframes * sizeof(float) );
102 buffer = state->control_port_buffer;
104 for (i = 0; i < (int)state->descriptor->PortCount; i++)
105 if ( LADSPA_IS_PORT_CONTROL(state->descriptor->PortDescriptors[i]) &&
106 LADSPA_IS_PORT_INPUT(state->descriptor->PortDescriptors[i]) )
108 state->descriptor->connect_port(state->handle, i, buffer);
109 buffer += jack_get_buffer_size(state->jack_client);
112 return 0;
115 /* Initializes JACK, opening the appropriate ports, instantiating the LADSPA
116 * Plugin, and starting the synthesis thread running.. Returns 1 on success. On
117 * failure, returns 0 and sets *error to an appropriate error message.
119 int init_jack(state_t *state, const char **error)
121 static char client_name_prefix[] = "jackspa_";
122 int err = 0;
123 jack_status_t jack_status;
124 int i;
125 unsigned long flags;
126 float *buffer;
128 /* Allocate memory for the client name. */
129 state->client_name = (char *)calloc
130 (1, sizeof(client_name_prefix) + strlen(state->descriptor->Label));
131 if (!state->client_name)
132 err = 1, *error = strerror(errno);
134 /* Set the client name. */
135 if (!err) {
136 strcat(state->client_name, client_name_prefix);
137 strcat(state->client_name, state->descriptor->Label);
140 /* Open JACK. */
141 if (!err) {
142 state->jack_client =
143 jack_client_open(state->client_name, JackNullOption, &jack_status);
144 if (jack_status)
145 err = 1, *error = "could not connect to JACK";
148 /* Allocate memory for the list of ports. */
149 if (!err) {
150 state->ports = (jack_port_t **)calloc
151 (state->descriptor->PortCount, sizeof(jack_port_t *));
152 if (!state->ports)
153 err = 1, *error = strerror(errno);
156 /* Allocate memory for the list of control port values. */
157 if (!err) {
158 state->control_port_values =
159 (float *)malloc(state->descriptor->PortCount * sizeof(float));
160 if (!state->control_port_values)
161 err = 1, *error = strerror(errno);
164 /* Register ports. */
165 state->num_control_ports = 0;
166 for (i = 0; !err && i < (int)state->descriptor->PortCount; i++) {
167 if ( LADSPA_IS_PORT_CONTROL(state->descriptor-> PortDescriptors[i]) &&
168 LADSPA_IS_PORT_INPUT(state->descriptor->PortDescriptors[i]) )
170 state->num_control_ports++;
171 continue;
174 if (LADSPA_IS_PORT_INPUT(state->descriptor->PortDescriptors[i]))
175 flags = JackPortIsInput;
176 else
177 flags = JackPortIsOutput;
179 state->ports[i] = jack_port_register
180 ( state->jack_client, state->descriptor->PortNames[i],
181 JACK_DEFAULT_AUDIO_TYPE, flags, 0 );
183 if (!state->ports[i])
184 err = 1, *error = "could not register JACK ports";
187 /* Register our processing callback. */
188 if (!err)
189 if (jack_set_process_callback(state->jack_client, &process, state))
190 err = 1, *error = "could not register the JACK processing callback";
192 /* Register our buffer size callback. */
193 if (!err)
194 if ( jack_set_buffer_size_callback
195 (state->jack_client, &buffer_size, state) )
196 err = 1, *error = "could not register the JACK processing callback";
198 /* Instantiate the LADSPA plugin. */
199 if (!err) {
200 state->handle = state->descriptor->instantiate
201 (state->descriptor, jack_get_sample_rate(state->jack_client));
202 if (!state->handle)
203 err = 1, *error = "could not instantiate the plugin.";
206 /* Allocate control port buffers. */
207 if (!err) {
208 state->control_port_buffer = (float *)malloc
209 ( state->num_control_ports *
210 jack_get_buffer_size(state->jack_client) *
211 sizeof(float) );
212 if (!state->control_port_buffer)
213 err = 1, *error = strerror(errno);
216 /* Connect control ports. */
217 if (!err) {
218 buffer = state->control_port_buffer;
220 for (i = 0; i < (int)state->descriptor->PortCount; i++)
221 if ( LADSPA_IS_PORT_CONTROL(state->descriptor->PortDescriptors[i]) &&
222 LADSPA_IS_PORT_INPUT(state->descriptor->PortDescriptors[i]))
224 state->descriptor->connect_port(state->handle, i, buffer);
225 buffer += jack_get_buffer_size(state->jack_client);
226 state->control_port_values[i] = 0.0;
230 /* Activate the LADSPA plugin. */
231 if (!err)
232 if (state->descriptor->activate)
233 state->descriptor->activate(state->handle);
235 /* Get the bits flowing. */
236 if (!err)
237 if (jack_activate(state->jack_client))
238 err = 1, *error = "could not activate audio processing";
240 return !err;
243 typedef enum {
244 st_want_plugin_file,
245 st_want_plugin_id,
246 st_done
247 } arg_parser_state;
249 /* Parses command-line arguments. Returns 1 on success. On failure, returns 0
250 * and sets *error to an appropriate error message.
252 int parse_args(state_t *state, int argc, char **argv, char **plugin_file,
253 int *plugin_id, const char **error)
255 int err = 0;
256 int i;
257 arg_parser_state st = st_want_plugin_file;
259 argc--;
260 argv++;
262 for (i = 0; i < argc; i++)
263 switch (st) {
264 case st_want_plugin_file:
265 *plugin_file = argv[i];
266 st = st_want_plugin_id;
267 break;
269 case st_want_plugin_id:
270 *plugin_id = atoi(argv[i]);
271 st = st_done;
272 break;
274 case st_done:
275 default:
276 break;
279 if (st != st_done)
280 err = 1, *error = "must supply a plugin file and a plugin ID";
282 return !err;
285 int jackspa_init(state_t *state, int argc, char **argv)
287 const char *error;
288 int err = 0;
289 char *plugin_file;
290 int plugin_id;
292 state->jack_client = 0;
294 err = !parse_args(state, argc, argv, &plugin_file, &plugin_id, &error);
296 if (!err)
297 err = !find_plugin(state, plugin_file, plugin_id, &error);
299 if (!err)
300 err = !init_jack(state, &error);
302 if (err)
303 fprintf(stderr, "jackspa error: %s\n", error);
305 return !err;