.gitignore
[ng-jackspa.git] / jackspa.cpp
blobb175e5211922aea008adf1c266703dd9814056ec
1 // jackspa, a dirt-simple LADSPA host for JACK
2 // Copyright (C) 2007 Nick Thomas
3 // Copyright (C) 2013 GĂ©raud Meyer <graud@gmx.com>
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of version 2 of the GNU General Public
7 // License as published by the Free Software Foundation; the terms of
8 // any later version are NOT APPLICABLE.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License along
16 // with this program; if not, write to the Free Software Foundation, Inc.,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 #include <dlfcn.h>
20 #include <errno.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include "jackspa.hpp"
26 // Finds the plugin descriptor with the given ID in the given
27 // object file, storing it in state->descriptor. Returns 1 on
28 // success. On failure, returns 0 and sets *error to an appropriate
29 // error message.
30 int find_plugin(state_t *state, char *file, int id, const char **error)
32 int err = 0;
33 int i;
34 void *library;
35 LADSPA_Descriptor *(*descriptor_fun)(unsigned long index);
36 LADSPA_Descriptor *descriptor;
38 // Open the library.
39 library = dlopen(file, RTLD_LAZY);
40 if (!library) {
41 *error = dlerror();
42 err = 1;
45 // Find the ladspa_descriptor() function.
46 if (!err) {
47 descriptor_fun = (LADSPA_Descriptor *(*)(unsigned long))
48 dlsym(library, "ladspa_descriptor");
49 if (!descriptor_fun) {
50 *error = dlerror();
51 err = 1;
55 // Find the appropriate descriptor.
56 for (i = 0; !err; i++) {
57 descriptor = descriptor_fun(i);
59 if (!descriptor) {
60 *error = "no such plugin index in the given file";
61 err = 1;
62 } else if ((int)descriptor->UniqueID == id) {
63 state->descriptor = descriptor;
64 break;
68 return !err;
71 // The JACK processing callback.
72 int process(jack_nframes_t nframes, void *arg)
74 state_t *state = (state_t *)arg;
75 int i, j;
76 float *buffer = state->control_port_buffer;
78 // Connect audio ports and copy control port values.
79 for (i = 0; i < (int)state->descriptor->PortCount; i++) {
80 if (LADSPA_IS_PORT_CONTROL(state->descriptor->PortDescriptors[i]) &&
81 LADSPA_IS_PORT_INPUT(state->descriptor->PortDescriptors[i])) {
82 for (j = 0; j < (int)nframes; j++, buffer++) {
83 *buffer = state->control_port_values[i];
85 } else {
86 state->descriptor->connect_port
87 (state->handle, i,
88 (float *)jack_port_get_buffer(state->ports[i], nframes));
92 // Run the plugin.
93 state->descriptor->run(state->handle, nframes);
95 return 0;
98 // The JACK buffer size callback.
99 int buffer_size(jack_nframes_t nframes, void *arg)
101 state_t *state = (state_t *)arg;
102 float *buffer;
103 int i;
105 state->control_port_buffer = (float *)realloc
106 (state->control_port_buffer, state->num_control_ports *
107 nframes * sizeof(float));
109 buffer = state->control_port_buffer;
111 for (i = 0; i < (int)state->descriptor->PortCount; i++) {
112 if (LADSPA_IS_PORT_CONTROL(state->descriptor->
113 PortDescriptors[i]) &&
114 LADSPA_IS_PORT_INPUT(state->descriptor->PortDescriptors[i])) {
115 state->descriptor->connect_port(state->handle, i, buffer);
116 buffer += jack_get_buffer_size(state->jack_client);
120 return 0;
123 // Initializes JACK, opening the appropriate ports, instantiating the
124 // LADSPA Plugin, and starting the synthesis thread running.. Returns
125 // 1 on success. On failure, returns 0 and sets *error to an
126 // appropriate error message.
127 int init_jack(state_t *state, const char **error)
129 static char client_name_prefix[] = "jackspa_";
130 int err = 0;
131 jack_status_t jack_status;
132 int i;
133 unsigned long flags;
134 float *buffer;
136 // Allocate memory for the client name.
137 state->client_name = (char *)calloc(1, sizeof(client_name_prefix) +
138 strlen(state->descriptor->Label));
139 if (!state->client_name) {
140 err = 1;
141 *error = strerror(errno);
144 // Set the client name.
145 if (!err) {
146 strcat(state->client_name, client_name_prefix);
147 strcat(state->client_name, state->descriptor->Label);
150 // Open JACK.
151 if (!err) {
152 state->jack_client = jack_client_open(state->client_name,
153 JackNullOption, &jack_status);
154 if (jack_status) {
155 *error = "could not connect to JACK";
156 err = 1;
160 // Allocate memory for the list of ports.
161 if (!err) {
162 state->ports = (jack_port_t **)calloc(state->descriptor->PortCount,
163 sizeof(jack_port_t *));
164 if (!state->ports) {
165 *error = strerror(errno);
166 err = 1;
170 // Allocate memory for the list of control port values.
171 if (!err) {
172 state->control_port_values =
173 (float *)malloc(state->descriptor->PortCount * sizeof(float));
174 if (!state->control_port_values) {
175 *error = strerror(errno);
176 err = 1;
180 // Register ports.
181 state->num_control_ports = 0;
182 for (i = 0; !err && i < (int)state->descriptor->PortCount; i++) {
183 if (LADSPA_IS_PORT_CONTROL(state->descriptor->
184 PortDescriptors[i]) &&
185 LADSPA_IS_PORT_INPUT(state->descriptor->PortDescriptors[i])) {
186 state->num_control_ports++;
187 continue;
190 if (LADSPA_IS_PORT_INPUT(state->descriptor->PortDescriptors[i])) {
191 flags = JackPortIsInput;
192 } else {
193 flags = JackPortIsOutput;
196 state->ports[i] =
197 jack_port_register(state->jack_client,
198 state->descriptor->PortNames[i],
199 JACK_DEFAULT_AUDIO_TYPE,
200 flags, 0);
202 if (!state->ports[i]) {
203 err = 1;
204 *error = "could not register JACK ports";
208 // Register our processing callback.
209 if (!err) {
210 if (jack_set_process_callback(state->jack_client, &process, state)) {
211 err = 1;
212 *error = "could not register the JACK processing callback";
216 // Register our buffer size callback.
217 if (!err) {
218 if (jack_set_buffer_size_callback(state->jack_client, &buffer_size,
219 state)) {
220 err = 1;
221 *error = "could not register the JACK processing callback";
225 // Instantiate the LADSPA plugin.
226 if (!err) {
227 state->handle = state->descriptor->instantiate
228 (state->descriptor, jack_get_sample_rate(state->jack_client));
229 if (!state->handle) {
230 err = 1;
231 *error = "could not instantiate the plugin.";
235 // Allocate control port buffers.
236 if (!err) {
237 state->control_port_buffer = (float *)malloc
238 (state->num_control_ports *
239 jack_get_buffer_size(state->jack_client) *
240 sizeof(float));
241 if (!state->control_port_buffer) {
242 err = 1;
243 *error = strerror(errno);
247 // Connect control ports.
248 if (!err) {
249 buffer = state->control_port_buffer;
251 for (i = 0; i < (int)state->descriptor->PortCount; i++) {
252 if (LADSPA_IS_PORT_CONTROL(state->descriptor->
253 PortDescriptors[i]) &&
254 LADSPA_IS_PORT_INPUT(state->descriptor->PortDescriptors[i])) {
255 state->descriptor->connect_port(state->handle, i, buffer);
256 buffer += jack_get_buffer_size(state->jack_client);
257 state->control_port_values[i] = 0.0;
262 // Activate the LADSPA plugin.
263 if (!err) {
264 if (state->descriptor->activate) {
265 state->descriptor->activate(state->handle);
269 // Get the bits flowing.
270 if (!err) {
271 if (jack_activate(state->jack_client)) {
272 err = 1;
273 *error = "could not activate audio processing";
277 return !err;
280 typedef enum {
281 st_want_plugin_file,
282 st_want_plugin_id,
283 st_done
284 } arg_parser_state;
286 // Parses command-line arguments. Returns 1 on success. On failure,
287 // returns 0 and sets *error to an appropriate error message.
288 int parse_args(state_t *state, int argc, char **argv, char **plugin_file,
289 int *plugin_id, const char **error)
291 int err = 0;
292 int i;
293 arg_parser_state st = st_want_plugin_file;
295 argc--;
296 argv++;
298 for (i = 0; i < argc; i++) {
299 switch (st) {
300 case st_want_plugin_file:
301 *plugin_file = argv[i];
302 st = st_want_plugin_id;
303 break;
305 case st_want_plugin_id:
306 *plugin_id = atoi(argv[i]);
307 st = st_done;
308 break;
310 case st_done:
311 break;
313 default:
314 break;
318 if (st != st_done) {
319 err = 1;
320 *error = "must supply a plugin file and a plugin ID";
323 return !err;
326 void jackspa_init(state_t *state, int argc, char **argv)
328 const char *error;
329 int err = 0;
330 char *plugin_file;
331 int plugin_id;
333 state->jack_client = 0;
335 err = !parse_args(state, argc, argv, &plugin_file, &plugin_id, &error);
337 if (!err) {
338 err = !find_plugin(state, plugin_file, plugin_id, &error);
341 if (!err) {
342 err = !init_jack(state, &error);
345 if (err) {
346 fprintf(stderr, "Error: %s.\n", error);